@@ -74,11 +74,11 @@ static int _dispatch_pthread_sigmask(int how, sigset_t *set, sigset_t *oset);
74
74
#endif
75
75
76
76
#if DISPATCH_COCOA_COMPAT
77
- static dispatch_once_t _dispatch_main_q_port_pred ;
77
+ static dispatch_once_t _dispatch_main_q_handle_pred ;
78
78
static void _dispatch_runloop_queue_poke (dispatch_queue_t dq ,
79
79
pthread_priority_t pp , dispatch_wakeup_flags_t flags );
80
- static void _dispatch_runloop_queue_port_init (void * ctxt );
81
- static void _dispatch_runloop_queue_port_dispose (dispatch_queue_t dq );
80
+ static void _dispatch_runloop_queue_handle_init (void * ctxt );
81
+ static void _dispatch_runloop_queue_handle_dispose (dispatch_queue_t dq );
82
82
#endif
83
83
84
84
static void _dispatch_root_queues_init_once (void * context );
@@ -4058,6 +4058,49 @@ _dispatch_queue_wakeup(dispatch_queue_t dq, pthread_priority_t pp,
4058
4058
}
4059
4059
}
4060
4060
4061
+ #if DISPATCH_COCOA_COMPAT
4062
+ DISPATCH_ALWAYS_INLINE
4063
+ static inline bool
4064
+ _dispatch_runloop_handle_is_valid (dispatch_runloop_handle_t handle )
4065
+ {
4066
+ #if TARGET_OS_MAC
4067
+ return MACH_PORT_VALID (handle );
4068
+ #elif defined(__linux__ )
4069
+ return handle >= 0 ;
4070
+ #else
4071
+ #error "runloop support not implemented on this platform"
4072
+ #endif
4073
+ }
4074
+
4075
+ DISPATCH_ALWAYS_INLINE
4076
+ static inline dispatch_runloop_handle_t
4077
+ _dispatch_runloop_queue_get_handle (dispatch_queue_t dq )
4078
+ {
4079
+ #if TARGET_OS_MAC
4080
+ return ((dispatch_runloop_handle_t )(uintptr_t )dq -> do_ctxt );
4081
+ #elif defined(__linux__ )
4082
+ // decode: 0 is a valid fd, so offset by 1 to distinguish from NULL
4083
+ return ((dispatch_runloop_handle_t )(uintptr_t )dq -> do_ctxt ) - 1 ;
4084
+ #else
4085
+ #error "runloop support not implemented on this platform"
4086
+ #endif
4087
+ }
4088
+
4089
+ DISPATCH_ALWAYS_INLINE
4090
+ static inline void
4091
+ _dispatch_runloop_queue_set_handle (dispatch_queue_t dq , dispatch_runloop_handle_t handle )
4092
+ {
4093
+ #if TARGET_OS_MAC
4094
+ dq -> do_ctxt = (void * )(uintptr_t )handle ;
4095
+ #elif defined(__linux__ )
4096
+ // encode: 0 is a valid fd, so offset by 1 to distinguish from NULL
4097
+ dq -> do_ctxt = (void * )(uintptr_t )(handle + 1 );
4098
+ #else
4099
+ #error "runloop support not implemented on this platform"
4100
+ #endif
4101
+ }
4102
+ #endif // DISPATCH_COCOA_COMPAT
4103
+
4061
4104
void
4062
4105
_dispatch_runloop_queue_wakeup (dispatch_queue_t dq , pthread_priority_t pp ,
4063
4106
dispatch_wakeup_flags_t flags )
@@ -4084,8 +4127,6 @@ _dispatch_runloop_queue_wakeup(dispatch_queue_t dq, pthread_priority_t pp,
4084
4127
if (flags & DISPATCH_WAKEUP_CONSUME ) {
4085
4128
return _dispatch_release_tailcall (dq );
4086
4129
}
4087
- #elif defined(__linux__ )
4088
- LINUX_PORT_ERROR ();
4089
4130
#else
4090
4131
return _dispatch_queue_wakeup (dq , pp , flags );
4091
4132
#endif
@@ -4122,10 +4163,13 @@ _dispatch_root_queue_wakeup(dispatch_queue_t dq,
4122
4163
static inline void
4123
4164
_dispatch_runloop_queue_class_poke (dispatch_queue_t dq )
4124
4165
{
4125
- mach_port_t mp = ( mach_port_t ) dq -> do_ctxt ;
4126
- if (!mp ) {
4166
+ dispatch_runloop_handle_t handle = _dispatch_runloop_queue_get_handle ( dq ) ;
4167
+ if (!_dispatch_runloop_handle_is_valid ( handle ) ) {
4127
4168
return ;
4128
4169
}
4170
+
4171
+ #if TARGET_OS_MAC
4172
+ mach_port_t mp = handle ;
4129
4173
kern_return_t kr = _dispatch_send_wakeup_runloop_thread (mp , 0 );
4130
4174
switch (kr ) {
4131
4175
case MACH_SEND_TIMEOUT :
@@ -4136,6 +4180,15 @@ _dispatch_runloop_queue_class_poke(dispatch_queue_t dq)
4136
4180
(void )dispatch_assume_zero (kr );
4137
4181
break ;
4138
4182
}
4183
+ #elif defined(__linux__ )
4184
+ int result ;
4185
+ do {
4186
+ result = eventfd_write (handle , 1 );
4187
+ } while (result == -1 && errno == EINTR );
4188
+ (void )dispatch_assume_zero (result );
4189
+ #else
4190
+ #error "runloop support not implemented on this platform"
4191
+ #endif
4139
4192
}
4140
4193
4141
4194
DISPATCH_NOINLINE
@@ -4150,8 +4203,8 @@ _dispatch_runloop_queue_poke(dispatch_queue_t dq,
4150
4203
// or in _dispatch_queue_cleanup2() for the main thread.
4151
4204
4152
4205
if (dq == & _dispatch_main_q ) {
4153
- dispatch_once_f (& _dispatch_main_q_port_pred , dq ,
4154
- _dispatch_runloop_queue_port_init );
4206
+ dispatch_once_f (& _dispatch_main_q_handle_pred , dq ,
4207
+ _dispatch_runloop_queue_handle_init );
4155
4208
}
4156
4209
_dispatch_queue_override_priority (dq , /* inout */ & pp , /* inout */ & flags );
4157
4210
if (flags & DISPATCH_WAKEUP_OVERRIDING ) {
@@ -4493,8 +4546,8 @@ _dispatch_main_queue_drain(void)
4493
4546
" from the wrong thread" );
4494
4547
}
4495
4548
4496
- dispatch_once_f (& _dispatch_main_q_port_pred , dq ,
4497
- _dispatch_runloop_queue_port_init );
4549
+ dispatch_once_f (& _dispatch_main_q_handle_pred , dq ,
4550
+ _dispatch_runloop_queue_handle_init );
4498
4551
4499
4552
_dispatch_perfmon_start ();
4500
4553
// <rdar://problem/23256682> hide the frame chaining when CFRunLoop
@@ -5544,7 +5597,7 @@ _dispatch_runloop_root_queue_create_4CF(const char *label, unsigned long flags)
5544
5597
_dispatch_queue_init (dq , DQF_THREAD_BOUND | DQF_CANNOT_TRYSYNC , 1 , false);
5545
5598
dq -> do_targetq = _dispatch_get_root_queue (_DISPATCH_QOS_CLASS_DEFAULT ,true);
5546
5599
dq -> dq_label = label ? label : "runloop-queue" ; // no-copy contract
5547
- _dispatch_runloop_queue_port_init (dq );
5600
+ _dispatch_runloop_queue_handle_init (dq );
5548
5601
_dispatch_queue_set_bound_thread (dq );
5549
5602
_dispatch_object_debug (dq , "%s" , __func__ );
5550
5603
return _dispatch_introspection_queue_create (dq );
@@ -5566,7 +5619,7 @@ _dispatch_runloop_queue_dispose(dispatch_queue_t dq)
5566
5619
{
5567
5620
_dispatch_object_debug (dq , "%s" , __func__ );
5568
5621
_dispatch_introspection_queue_dispose (dq );
5569
- _dispatch_runloop_queue_port_dispose (dq );
5622
+ _dispatch_runloop_queue_handle_dispose (dq );
5570
5623
_dispatch_queue_destroy (dq );
5571
5624
}
5572
5625
@@ -5591,23 +5644,26 @@ _dispatch_runloop_root_queue_wakeup_4CF(dispatch_queue_t dq)
5591
5644
_dispatch_runloop_queue_wakeup (dq , 0 , false);
5592
5645
}
5593
5646
5594
- mach_port_t
5647
+ dispatch_runloop_handle_t
5595
5648
_dispatch_runloop_root_queue_get_port_4CF (dispatch_queue_t dq )
5596
5649
{
5597
5650
if (slowpath (dq -> do_vtable != DISPATCH_VTABLE (queue_runloop ))) {
5598
5651
DISPATCH_CLIENT_CRASH (dq -> do_vtable , "Not a runloop queue" );
5599
5652
}
5600
- return ( mach_port_t ) dq -> do_ctxt ;
5653
+ return _dispatch_runloop_queue_get_handle ( dq ) ;
5601
5654
}
5602
5655
5603
5656
static void
5604
- _dispatch_runloop_queue_port_init (void * ctxt )
5657
+ _dispatch_runloop_queue_handle_init (void * ctxt )
5605
5658
{
5606
5659
dispatch_queue_t dq = (dispatch_queue_t )ctxt ;
5607
- mach_port_t mp ;
5608
- kern_return_t kr ;
5660
+ dispatch_runloop_handle_t handle ;
5609
5661
5610
5662
_dispatch_fork_becomes_unsafe ();
5663
+
5664
+ #if TARGET_OS_MAC
5665
+ mach_port_t mp ;
5666
+ kern_return_t kr ;
5611
5667
kr = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE , & mp );
5612
5668
DISPATCH_VERIFY_MIG (kr );
5613
5669
(void )dispatch_assume_zero (kr );
@@ -5625,38 +5681,81 @@ _dispatch_runloop_queue_port_init(void *ctxt)
5625
5681
DISPATCH_VERIFY_MIG (kr );
5626
5682
(void )dispatch_assume_zero (kr );
5627
5683
}
5628
- dq -> do_ctxt = (void * )(uintptr_t )mp ;
5684
+ handle = mp ;
5685
+ #elif defined(__linux__ )
5686
+ int fd = eventfd (0 , EFD_CLOEXEC | EFD_NONBLOCK );
5687
+ if (fd == -1 ) {
5688
+ int err = errno ;
5689
+ switch (err ) {
5690
+ case EMFILE :
5691
+ DISPATCH_CLIENT_CRASH (err , "eventfd() failure: "
5692
+ "process is out of file descriptors" );
5693
+ break ;
5694
+ case ENFILE :
5695
+ DISPATCH_CLIENT_CRASH (err , "eventfd() failure: "
5696
+ "system is out of file descriptors" );
5697
+ break ;
5698
+ case ENOMEM :
5699
+ DISPATCH_CLIENT_CRASH (err , "eventfd() failure: "
5700
+ "kernel is out of memory" );
5701
+ break ;
5702
+ default :
5703
+ DISPATCH_INTERNAL_CRASH (err , "eventfd() failure" );
5704
+ break ;
5705
+ }
5706
+ }
5707
+ handle = fd ;
5708
+ #else
5709
+ #error "runloop support not implemented on this platform"
5710
+ #endif
5711
+ _dispatch_runloop_queue_set_handle (dq , handle );
5629
5712
5630
5713
_dispatch_program_is_probably_callback_driven = true;
5631
5714
}
5632
5715
5633
5716
static void
5634
- _dispatch_runloop_queue_port_dispose (dispatch_queue_t dq )
5717
+ _dispatch_runloop_queue_handle_dispose (dispatch_queue_t dq )
5635
5718
{
5636
- mach_port_t mp = ( mach_port_t ) dq -> do_ctxt ;
5637
- if (!mp ) {
5719
+ dispatch_runloop_handle_t handle = _dispatch_runloop_queue_get_handle ( dq ) ;
5720
+ if (!_dispatch_runloop_handle_is_valid ( handle ) ) {
5638
5721
return ;
5639
5722
}
5640
5723
dq -> do_ctxt = NULL ;
5724
+ #if TARGET_OS_MAC
5725
+ mach_port_t mp = handle ;
5641
5726
kern_return_t kr = mach_port_deallocate (mach_task_self (), mp );
5642
5727
DISPATCH_VERIFY_MIG (kr );
5643
5728
(void )dispatch_assume_zero (kr );
5644
5729
kr = mach_port_mod_refs (mach_task_self (), mp , MACH_PORT_RIGHT_RECEIVE , -1 );
5645
5730
DISPATCH_VERIFY_MIG (kr );
5646
5731
(void )dispatch_assume_zero (kr );
5732
+ #elif defined(__linux__ )
5733
+ int rc = close (handle );
5734
+ (void )dispatch_assume_zero (rc );
5735
+ #else
5736
+ #error "runloop support not implemented on this platform"
5737
+ #endif
5647
5738
}
5648
5739
5649
5740
#pragma mark -
5650
5741
#pragma mark dispatch_main_queue
5651
5742
5652
- mach_port_t
5653
- _dispatch_get_main_queue_port_4CF (void )
5743
+ dispatch_runloop_handle_t
5744
+ _dispatch_get_main_queue_handle_4CF (void )
5654
5745
{
5655
5746
dispatch_queue_t dq = & _dispatch_main_q ;
5656
- dispatch_once_f (& _dispatch_main_q_port_pred , dq ,
5657
- _dispatch_runloop_queue_port_init );
5658
- return (mach_port_t )dq -> do_ctxt ;
5747
+ dispatch_once_f (& _dispatch_main_q_handle_pred , dq ,
5748
+ _dispatch_runloop_queue_handle_init );
5749
+ return _dispatch_runloop_queue_get_handle (dq );
5750
+ }
5751
+
5752
+ #if TARGET_OS_MAC
5753
+ dispatch_runloop_handle_t
5754
+ _dispatch_get_main_queue_port_4CF (void )
5755
+ {
5756
+ return _dispatch_get_main_queue_handle_4CF ();
5659
5757
}
5758
+ #endif
5660
5759
5661
5760
static bool main_q_is_draining ;
5662
5761
@@ -5670,7 +5769,7 @@ _dispatch_queue_set_mainq_drain_state(bool arg)
5670
5769
}
5671
5770
5672
5771
void
5673
- _dispatch_main_queue_callback_4CF (mach_msg_header_t * msg DISPATCH_UNUSED )
5772
+ _dispatch_main_queue_callback_4CF (void * ignored DISPATCH_UNUSED )
5674
5773
{
5675
5774
if (main_q_is_draining ) {
5676
5775
return ;
@@ -5795,9 +5894,9 @@ _dispatch_queue_cleanup2(void)
5795
5894
#endif
5796
5895
5797
5896
#if DISPATCH_COCOA_COMPAT
5798
- dispatch_once_f (& _dispatch_main_q_port_pred , dq ,
5799
- _dispatch_runloop_queue_port_init );
5800
- _dispatch_runloop_queue_port_dispose (dq );
5897
+ dispatch_once_f (& _dispatch_main_q_handle_pred , dq ,
5898
+ _dispatch_runloop_queue_handle_init );
5899
+ _dispatch_runloop_queue_handle_dispose (dq );
5801
5900
#endif
5802
5901
}
5803
5902
0 commit comments