@@ -35,7 +35,7 @@ extern void objc_terminate(void);
35
35
36
36
#include "CFOverflow.h"
37
37
38
- #if TARGET_OS_MAC || TARGET_OS_WIN32 || !DEPLOYMENT_RUNTIME_OBJC
38
+ #if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_BSD || !DEPLOYMENT_RUNTIME_OBJC
39
39
#define USE_DISPATCH_SOURCE_FOR_TIMERS __HAS_DISPATCH__
40
40
#else
41
41
#define USE_DISPATCH_SOURCE_FOR_TIMERS 0
@@ -65,6 +65,8 @@ typedef mach_port_t dispatch_runloop_handle_t;
65
65
typedef int dispatch_runloop_handle_t ;
66
66
#elif TARGET_OS_WIN32
67
67
typedef HANDLE dispatch_runloop_handle_t ;
68
+ #else
69
+ typedef uint64_t dispatch_runloop_handle_t ;
68
70
#endif
69
71
70
72
#if TARGET_OS_MAC
@@ -106,9 +108,12 @@ DISPATCH_EXPORT void _dispatch_main_queue_callback_4CF(void * _Null_unspecified)
106
108
dispatch_runloop_handle_t _dispatch_get_main_queue_port_4CF (void );
107
109
extern void _dispatch_main_queue_callback_4CF (void * _Null_unspecified msg );
108
110
111
+ #else
112
+ dispatch_runloop_handle_t _dispatch_get_main_queue_port_4CF (void );
113
+ extern void _dispatch_main_queue_callback_4CF (void * _Null_unspecified msg );
109
114
#endif
110
115
111
- #if TARGET_OS_WIN32 || TARGET_OS_LINUX
116
+ #if TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_BSD
112
117
CF_EXPORT _CFThreadRef _CF_pthread_main_thread_np (void );
113
118
#define pthread_main_thread_np () _CF_pthread_main_thread_np()
114
119
#endif
@@ -448,6 +453,267 @@ CF_INLINE kern_return_t __CFPortSetRemove(__CFPort port, __CFPortSet portSet) {
448
453
CF_INLINE void __CFPortSetFree (__CFPortSet portSet ) {
449
454
close (portSet );
450
455
}
456
+ #elif TARGET_OS_BSD
457
+
458
+ #include <sys/types.h>
459
+ #include <sys/event.h>
460
+ #include <sys/time.h>
461
+ #include <poll.h>
462
+
463
+ typedef uint64_t __CFPort ;
464
+ #define CFPORT_NULL ((__CFPort)-1)
465
+
466
+ // _dispatch_get_main_queue_port_4CF is a uint64_t, i.e., a __CFPort.
467
+ // That is, we can't use one type for the queue handle in Dispatch and a
468
+ // different type for __CFPort in CF.
469
+ #define __CFPORT_PACK (rfd , wfd ) (((uint64_t)(rfd) << 32) | ((uint32_t)(wfd)))
470
+ #define __CFPORT_UNPACK_W (port ) ((uint32_t)((port) & 0xffffffff))
471
+ #define __CFPORT_UNPACK_R (port ) ((uint32_t)((port) >> 32))
472
+
473
+ typedef struct ___CFPortSet {
474
+ int kq ;
475
+ } * __CFPortSet ;
476
+ #define CFPORTSET_NULL NULL
477
+
478
+ #define TIMEOUT_INFINITY UINT64_MAX
479
+
480
+ // Timers are not pipes; they are kevents on a parent kqueue.
481
+ // We must flag these to differentiate them from pipes, but we have
482
+ // to pack the (kqueue, timer ident) pair like a __CFPort.
483
+ #define __CFPORT_TIMER_PACK (ident , kq ) \
484
+ ((1ULL << 63) | ((uint64_t)(ident) << 32) | ((uint32_t)(kq)))
485
+ #define __CFPORT_IS_TIMER (port ) ((port) & (1ULL << 63))
486
+
487
+ static __CFPort __CFPortAllocate (__unused uintptr_t guard ) {
488
+ __CFPort port ;
489
+ int fds [2 ];
490
+ int r = pipe2 (fds , O_CLOEXEC | O_NONBLOCK );
491
+ if (r == -1 ) {
492
+ return CFPORT_NULL ;
493
+ }
494
+
495
+ uint32_t rfd = (uint32_t )fds [0 ], wfd = (uint32_t )fds [1 ];
496
+ port = __CFPORT_PACK (rfd , wfd );
497
+
498
+ if (__CFPORT_IS_TIMER (port )) {
499
+ // This port is not distinguishable from a flagged packed timer.
500
+ close ((int )(__CFPORT_UNPACK_W (port )));
501
+ close ((int )(__CFPORT_UNPACK_R (port )));
502
+ return CFPORT_NULL ;
503
+ }
504
+
505
+ return port ;
506
+ }
507
+
508
+ static void __CFPortTrigger (__CFPort port ) {
509
+ int wfd = (int )__CFPORT_UNPACK_W (port );
510
+ ssize_t result ;
511
+ do {
512
+ result = write (wfd , "x" , 1 );
513
+ } while (result == -1 && errno == EINTR );
514
+ }
515
+
516
+ CF_INLINE void __CFPortFree (__CFPort port , __unused uintptr_t guard ) {
517
+ close ((int )(__CFPORT_UNPACK_W (port )));
518
+ close ((int )(__CFPORT_UNPACK_R (port )));
519
+ }
520
+
521
+ #define __CFPORT_TIMER_UNPACK_ID (port ) (((port) >> 32) & 0x7fffffff)
522
+ #define __CFPORT_TIMER_UNPACK_KQ (port ) ((port) & 0xffffffff)
523
+ #define MAX_TIMERS 16
524
+ uintptr_t ident = 0 ;
525
+
526
+ static __CFPort mk_timer_create (__CFPortSet parent ) {
527
+ if (ident > MAX_TIMERS ) return CFPORT_NULL ;
528
+ ident ++ ;
529
+
530
+ int kq = parent -> kq ;
531
+ __CFPort port = __CFPORT_TIMER_PACK (ident , kq );
532
+
533
+ return port ;
534
+ }
535
+
536
+ static kern_return_t mk_timer_arm (__CFPort timer , int64_t expire_tsr ) {
537
+ uint64_t now = mach_absolute_time ();
538
+ uint64_t expire_time = __CFTSRToNanoseconds (expire_tsr );
539
+ int64_t duration = 0 ;
540
+ if (now <= expire_time ) {
541
+ duration = __CFTSRToTimeInterval (expire_time - now ) * 1000 ;
542
+ }
543
+
544
+ int id = __CFPORT_TIMER_UNPACK_ID (timer );
545
+ struct kevent tev ;
546
+ EV_SET (
547
+ & tev ,
548
+ id ,
549
+ EVFILT_TIMER ,
550
+ EV_ADD | EV_ENABLE ,
551
+ 0 ,
552
+ duration ,
553
+ (void * )timer );
554
+
555
+ int kq = __CFPORT_TIMER_UNPACK_KQ (timer );
556
+ int r = kevent (kq , & tev , 1 , NULL , 0 , NULL );
557
+
558
+ return KERN_SUCCESS ;
559
+ }
560
+
561
+ static kern_return_t mk_timer_cancel (__CFPort timer , const void * unused ) {
562
+ int id = __CFPORT_TIMER_UNPACK_ID (timer );
563
+ struct kevent tev ;
564
+ EV_SET (
565
+ & tev ,
566
+ id ,
567
+ EVFILT_TIMER ,
568
+ EV_DISABLE ,
569
+ 0 ,
570
+ 0 ,
571
+ (void * )timer );
572
+
573
+ int kq = __CFPORT_TIMER_UNPACK_KQ (timer );
574
+ int r = kevent (kq , & tev , 1 , NULL , 0 , NULL );
575
+
576
+ return KERN_SUCCESS ;
577
+ }
578
+
579
+ static kern_return_t mk_timer_destroy (__CFPort timer ) {
580
+ int id = __CFPORT_TIMER_UNPACK_ID (timer );
581
+ struct kevent tev ;
582
+ EV_SET (
583
+ & tev ,
584
+ id ,
585
+ EVFILT_TIMER ,
586
+ EV_DELETE ,
587
+ 0 ,
588
+ 0 ,
589
+ (void * )timer );
590
+
591
+ int kq = __CFPORT_TIMER_UNPACK_KQ (timer );
592
+ int r = kevent (kq , & tev , 1 , NULL , 0 , NULL );
593
+
594
+ ident -- ;
595
+ return KERN_SUCCESS ;
596
+ }
597
+
598
+ CF_INLINE __CFPortSet __CFPortSetAllocate (void ) {
599
+ struct ___CFPortSet * set = malloc (sizeof (struct ___CFPortSet ));
600
+ set -> kq = kqueue ();
601
+ return set ;
602
+ }
603
+
604
+ CF_INLINE kern_return_t __CFPortSetInsert (__CFPort port , __CFPortSet set ) {
605
+ if (__CFPORT_IS_TIMER (port )) {
606
+ return 0 ;
607
+ }
608
+
609
+ struct kevent change ;
610
+ EV_SET (& change ,
611
+ __CFPORT_UNPACK_R (port ),
612
+ EVFILT_READ ,
613
+ EV_ADD | EV_ENABLE | EV_CLEAR | EV_RECEIPT ,
614
+ 0 ,
615
+ 0 ,
616
+ (void * )port );
617
+ struct timespec timeout = {0 , 0 };
618
+ int r = kevent (set -> kq , & change , 1 , NULL , 0 , & timeout );
619
+
620
+ return 0 ;
621
+ }
622
+
623
+ CF_INLINE kern_return_t __CFPortSetRemove (__CFPort port , __CFPortSet set ) {
624
+ if (__CFPORT_IS_TIMER (port )) {
625
+ return 0 ;
626
+ }
627
+
628
+ struct kevent change ;
629
+ EV_SET (& change ,
630
+ __CFPORT_UNPACK_R (port ),
631
+ EVFILT_READ ,
632
+ EV_DELETE | EV_RECEIPT ,
633
+ 0 ,
634
+ 0 ,
635
+ (void * )port );
636
+ struct timespec timeout = {0 , 0 };
637
+ int r = kevent (set -> kq , & change , 1 , NULL , 0 , & timeout );
638
+
639
+ return 0 ;
640
+ }
641
+
642
+ CF_INLINE void __CFPortSetFree (__CFPortSet set ) {
643
+ close (set -> kq );
644
+ free (set );
645
+ }
646
+
647
+ static int __CFPollFileDescriptors (struct pollfd * fds , nfds_t nfds , uint64_t timeout ) {
648
+ uint64_t elapsed = 0 ;
649
+ uint64_t start = mach_absolute_time ();
650
+ int result = 0 ;
651
+ while (1 ) {
652
+ struct timespec ts = {0 };
653
+ struct timespec * tsPtr = & ts ;
654
+ if (timeout == TIMEOUT_INFINITY ) {
655
+ tsPtr = NULL ;
656
+ } else if (elapsed < timeout ) {
657
+ uint64_t delta = timeout - elapsed ;
658
+ ts .tv_sec = delta / 1000000000UL ;
659
+ ts .tv_nsec = delta % 1000000000UL ;
660
+ }
661
+
662
+ result = ppoll (fds , 1 , tsPtr , NULL );
663
+
664
+ if (result == -1 && errno == EINTR ) {
665
+ uint64_t end = mach_absolute_time ();
666
+ elapsed += (end - start );
667
+ start = end ;
668
+ } else {
669
+ return result ;
670
+ }
671
+ }
672
+ }
673
+
674
+ static Boolean __CFRunLoopServiceFileDescriptors (__CFPortSet set , __CFPort port , uint64_t timeout , __CFPort * livePort ) {
675
+ __CFPort awokenPort = CFPORT_NULL ;
676
+
677
+ if (port != CFPORT_NULL ) {
678
+ int rfd = __CFPORT_UNPACK_R (port );
679
+ struct pollfd fdInfo = {
680
+ .fd = rfd ,
681
+ .events = POLLIN ,
682
+ };
683
+
684
+ ssize_t result = __CFPollFileDescriptors (& fdInfo , 1 , timeout );
685
+ if (result == 0 )
686
+ return false;
687
+
688
+ awokenPort = port ;
689
+ } else {
690
+ struct kevent awake ;
691
+ struct timespec timeout = {0 , 0 };
692
+
693
+ int r = kevent (set -> kq , NULL , 0 , & awake , 1 , & timeout );
694
+
695
+ if (r == 0 ) {
696
+ return false;
697
+ }
698
+
699
+ if (awake .flags == EV_ERROR ) {
700
+ return false;
701
+ }
702
+
703
+ if (awake .filter == EVFILT_READ ) {
704
+ char x ;
705
+ r = read (awake .ident , & x , 1 );
706
+ }
707
+
708
+ awokenPort = (__CFPort )awake .udata ;
709
+ }
710
+
711
+ if (livePort )
712
+ * livePort = awokenPort ;
713
+
714
+ return true;
715
+ }
716
+
451
717
#else
452
718
#error "CFPort* stubs for this platform must be implemented
453
719
#endif
@@ -559,6 +825,11 @@ static kern_return_t mk_timer_cancel(HANDLE name, AbsoluteTime *result_time) {
559
825
}
560
826
return (int )res ;
561
827
}
828
+ #elif TARGET_OS_BSD
829
+ /*
830
+ * This implementation of the mk_timer_* stubs is defined with the
831
+ * implementation of the CFPort* stubs.
832
+ */
562
833
#else
563
834
#error "mk_timer_* stubs for this platform must be implemented"
564
835
#endif
@@ -841,10 +1112,14 @@ static CFRunLoopModeRef __CFRunLoopFindMode(CFRunLoopRef rl, CFStringRef modeNam
841
1112
842
1113
ret = __CFPortSetInsert (queuePort , rlm -> _portSet );
843
1114
if (KERN_SUCCESS != ret ) CRASH ("*** Unable to insert timer port into port set. (%d) ***" , ret );
844
-
845
1115
#endif
846
1116
#endif
1117
+ rlm -> _timerPort = CFPORT_NULL ;
1118
+ #if TARGET_OS_BSD
1119
+ rlm -> _timerPort = mk_timer_create (rlm -> _portSet );
1120
+ #else
847
1121
rlm -> _timerPort = mk_timer_create ();
1122
+ #endif
848
1123
if (rlm -> _timerPort == CFPORT_NULL ) {
849
1124
CRASH ("*** Unable to create timer Port (%d) ***" , rlm -> _timerPort );
850
1125
}
@@ -2670,6 +2945,8 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter
2670
2945
Boolean windowsMessageReceived = false;
2671
2946
#elif TARGET_OS_LINUX
2672
2947
int livePort = -1 ;
2948
+ #else
2949
+ __CFPort livePort = CFPORT_NULL ;
2673
2950
#endif
2674
2951
__CFPortSet waitSet = rlm -> _portSet ;
2675
2952
@@ -2707,6 +2984,12 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter
2707
2984
if (__CFRunLoopWaitForMultipleObjects (NULL , & dispatchPort , 0 , 0 , & livePort , NULL )) {
2708
2985
goto handle_msg ;
2709
2986
}
2987
+ #elif TARGET_OS_BSD
2988
+ if (__CFRunLoopServiceFileDescriptors (CFPORTSET_NULL , dispatchPort , 0 , & livePort )) {
2989
+ goto handle_msg ;
2990
+ }
2991
+ #else
2992
+ #error "invoking the port select implementation is required"
2710
2993
#endif
2711
2994
}
2712
2995
#endif
@@ -2762,6 +3045,10 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter
2762
3045
__CFRunLoopWaitForMultipleObjects (waitSet , NULL , poll ? 0 : TIMEOUT_INFINITY , rlm -> _msgQMask , & livePort , & windowsMessageReceived );
2763
3046
#elif TARGET_OS_LINUX
2764
3047
__CFRunLoopServiceFileDescriptors (waitSet , CFPORT_NULL , poll ? 0 : TIMEOUT_INFINITY , & livePort );
3048
+ #elif TARGET_OS_BSD
3049
+ __CFRunLoopServiceFileDescriptors (waitSet , CFPORT_NULL , poll ? 0 : TIMEOUT_INFINITY , & livePort );
3050
+ #else
3051
+ #error "invoking the port set select implementation is required"
2765
3052
#endif
2766
3053
2767
3054
__CFRunLoopLock (rl );
@@ -2877,7 +3164,7 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter
2877
3164
2878
3165
CFRUNLOOP_ARP_BEGIN ;
2879
3166
2880
- #if TARGET_OS_WIN32 || TARGET_OS_LINUX
3167
+ #if TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_BSD
2881
3168
void * msg = 0 ;
2882
3169
#endif
2883
3170
cf_trace (KDEBUG_EVENT_CFRL_IS_CALLING_DISPATCH | DBG_FUNC_START , rl , rlm , msg , livePort );
@@ -3060,6 +3347,10 @@ void CFRunLoopWakeUp(CFRunLoopRef rl) {
3060
3347
CFAssert1 (0 == ret , __kCFLogAssertion , "%s(): Unable to send wake message to eventfd" , __PRETTY_FUNCTION__ );
3061
3348
#elif TARGET_OS_WIN32
3062
3349
SetEvent (rl -> _wakeUpPort );
3350
+ #elif TARGET_OS_BSD
3351
+ __CFPortTrigger (rl -> _wakeUpPort );
3352
+ #else
3353
+ #error "required"
3063
3354
#endif
3064
3355
3065
3356
cf_trace (KDEBUG_EVENT_CFRL_WAKEUP | DBG_FUNC_END , rl , 0 , 0 , 0 );
0 commit comments