@@ -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 );
@@ -4063,6 +4063,48 @@ _dispatch_queue_wakeup(dispatch_queue_t dq, pthread_priority_t pp,
4063
4063
}
4064
4064
4065
4065
#if DISPATCH_COCOA_COMPAT
4066
+
4067
+ DISPATCH_ALWAYS_INLINE
4068
+ static inline bool
4069
+ _dispatch_runloop_handle_is_valid (dispatch_runloop_handle_t handle )
4070
+ {
4071
+ #if TARGET_OS_MAC
4072
+ return MACH_PORT_VALID (handle );
4073
+ #elif defined(__linux__ )
4074
+ return handle >= 0 ;
4075
+ #else
4076
+ #error "runloop support not implemented on this platform"
4077
+ #endif
4078
+ }
4079
+
4080
+ DISPATCH_ALWAYS_INLINE
4081
+ static inline dispatch_runloop_handle_t
4082
+ _dispatch_runloop_queue_get_handle (dispatch_queue_t dq )
4083
+ {
4084
+ #if TARGET_OS_MAC
4085
+ return ((dispatch_runloop_handle_t )(uintptr_t )dq -> do_ctxt );
4086
+ #elif defined(__linux__ )
4087
+ // decode: 0 is a valid fd, so offset by 1 to distinguish from NULL
4088
+ return ((dispatch_runloop_handle_t )(uintptr_t )dq -> do_ctxt ) - 1 ;
4089
+ #else
4090
+ #error "runloop support not implemented on this platform"
4091
+ #endif
4092
+ }
4093
+
4094
+ DISPATCH_ALWAYS_INLINE
4095
+ static inline void
4096
+ _dispatch_runloop_queue_set_handle (dispatch_queue_t dq , dispatch_runloop_handle_t handle )
4097
+ {
4098
+ #if TARGET_OS_MAC
4099
+ dq -> do_ctxt = (void * )(uintptr_t )handle ;
4100
+ #elif defined(__linux__ )
4101
+ // encode: 0 is a valid fd, so offset by 1 to distinguish from NULL
4102
+ dq -> do_ctxt = (void * )(uintptr_t )(handle + 1 );
4103
+ #else
4104
+ #error "runloop support not implemented on this platform"
4105
+ #endif
4106
+ }
4107
+
4066
4108
void
4067
4109
_dispatch_runloop_queue_wakeup (dispatch_queue_t dq , pthread_priority_t pp ,
4068
4110
dispatch_wakeup_flags_t flags )
@@ -4090,13 +4132,6 @@ _dispatch_runloop_queue_wakeup(dispatch_queue_t dq, pthread_priority_t pp,
4090
4132
return _dispatch_release_tailcall (dq );
4091
4133
}
4092
4134
}
4093
- #else
4094
- void
4095
- _dispatch_runloop_queue_wakeup (dispatch_queue_t dq , pthread_priority_t pp ,
4096
- dispatch_wakeup_flags_t flags )
4097
- {
4098
- LINUX_PORT_ERROR ();
4099
- }
4100
4135
#endif
4101
4136
4102
4137
void
@@ -4130,10 +4165,13 @@ _dispatch_root_queue_wakeup(dispatch_queue_t dq,
4130
4165
static inline void
4131
4166
_dispatch_runloop_queue_class_poke (dispatch_queue_t dq )
4132
4167
{
4133
- mach_port_t mp = ( mach_port_t ) dq -> do_ctxt ;
4134
- if (!mp ) {
4168
+ dispatch_runloop_handle_t handle = _dispatch_runloop_queue_get_handle ( dq ) ;
4169
+ if (!_dispatch_runloop_handle_is_valid ( handle ) ) {
4135
4170
return ;
4136
4171
}
4172
+
4173
+ #if TARGET_OS_MAC
4174
+ mach_port_t mp = handle ;
4137
4175
kern_return_t kr = _dispatch_send_wakeup_runloop_thread (mp , 0 );
4138
4176
switch (kr ) {
4139
4177
case MACH_SEND_TIMEOUT :
@@ -4144,6 +4182,15 @@ _dispatch_runloop_queue_class_poke(dispatch_queue_t dq)
4144
4182
(void )dispatch_assume_zero (kr );
4145
4183
break ;
4146
4184
}
4185
+ #elif defined(__linux__ )
4186
+ int result ;
4187
+ do {
4188
+ result = eventfd_write (handle , 1 );
4189
+ } while (result == -1 && errno == EINTR );
4190
+ (void )dispatch_assume_zero (result );
4191
+ #else
4192
+ #error "runloop support not implemented on this platform"
4193
+ #endif
4147
4194
}
4148
4195
4149
4196
DISPATCH_NOINLINE
@@ -4158,8 +4205,8 @@ _dispatch_runloop_queue_poke(dispatch_queue_t dq,
4158
4205
// or in _dispatch_queue_cleanup2() for the main thread.
4159
4206
4160
4207
if (dq == & _dispatch_main_q ) {
4161
- dispatch_once_f (& _dispatch_main_q_port_pred , dq ,
4162
- _dispatch_runloop_queue_port_init );
4208
+ dispatch_once_f (& _dispatch_main_q_handle_pred , dq ,
4209
+ _dispatch_runloop_queue_handle_init );
4163
4210
}
4164
4211
_dispatch_queue_override_priority (dq , /* inout */ & pp , /* inout */ & flags );
4165
4212
if (flags & DISPATCH_WAKEUP_OVERRIDING ) {
@@ -4501,8 +4548,8 @@ _dispatch_main_queue_drain(void)
4501
4548
" from the wrong thread" );
4502
4549
}
4503
4550
4504
- dispatch_once_f (& _dispatch_main_q_port_pred , dq ,
4505
- _dispatch_runloop_queue_port_init );
4551
+ dispatch_once_f (& _dispatch_main_q_handle_pred , dq ,
4552
+ _dispatch_runloop_queue_handle_init );
4506
4553
4507
4554
_dispatch_perfmon_start ();
4508
4555
// <rdar://problem/23256682> hide the frame chaining when CFRunLoop
@@ -5547,7 +5594,7 @@ _dispatch_runloop_root_queue_create_4CF(const char *label, unsigned long flags)
5547
5594
_dispatch_queue_init (dq , DQF_THREAD_BOUND | DQF_CANNOT_TRYSYNC , 1 , false);
5548
5595
dq -> do_targetq = _dispatch_get_root_queue (_DISPATCH_QOS_CLASS_DEFAULT ,true);
5549
5596
dq -> dq_label = label ? label : "runloop-queue" ; // no-copy contract
5550
- _dispatch_runloop_queue_port_init (dq );
5597
+ _dispatch_runloop_queue_handle_init (dq );
5551
5598
_dispatch_queue_set_bound_thread (dq );
5552
5599
_dispatch_object_debug (dq , "%s" , __func__ );
5553
5600
return _dispatch_introspection_queue_create (dq );
@@ -5569,7 +5616,7 @@ _dispatch_runloop_queue_dispose(dispatch_queue_t dq)
5569
5616
{
5570
5617
_dispatch_object_debug (dq , "%s" , __func__ );
5571
5618
_dispatch_introspection_queue_dispose (dq );
5572
- _dispatch_runloop_queue_port_dispose (dq );
5619
+ _dispatch_runloop_queue_handle_dispose (dq );
5573
5620
_dispatch_queue_destroy (dq );
5574
5621
}
5575
5622
@@ -5594,23 +5641,26 @@ _dispatch_runloop_root_queue_wakeup_4CF(dispatch_queue_t dq)
5594
5641
_dispatch_runloop_queue_wakeup (dq , 0 , false);
5595
5642
}
5596
5643
5597
- mach_port_t
5644
+ dispatch_runloop_handle_t
5598
5645
_dispatch_runloop_root_queue_get_port_4CF (dispatch_queue_t dq )
5599
5646
{
5600
5647
if (slowpath (dq -> do_vtable != DISPATCH_VTABLE (queue_runloop ))) {
5601
5648
DISPATCH_CLIENT_CRASH (dq -> do_vtable , "Not a runloop queue" );
5602
5649
}
5603
- return ( mach_port_t ) dq -> do_ctxt ;
5650
+ return _dispatch_runloop_queue_get_handle ( dq ) ;
5604
5651
}
5605
5652
5606
5653
static void
5607
- _dispatch_runloop_queue_port_init (void * ctxt )
5654
+ _dispatch_runloop_queue_handle_init (void * ctxt )
5608
5655
{
5609
5656
dispatch_queue_t dq = (dispatch_queue_t )ctxt ;
5610
- mach_port_t mp ;
5611
- kern_return_t kr ;
5657
+ dispatch_runloop_handle_t handle ;
5612
5658
5613
5659
_dispatch_fork_becomes_unsafe ();
5660
+
5661
+ #if TARGET_OS_MAC
5662
+ mach_port_t mp ;
5663
+ kern_return_t kr ;
5614
5664
kr = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE , & mp );
5615
5665
DISPATCH_VERIFY_MIG (kr );
5616
5666
(void )dispatch_assume_zero (kr );
@@ -5628,38 +5678,81 @@ _dispatch_runloop_queue_port_init(void *ctxt)
5628
5678
DISPATCH_VERIFY_MIG (kr );
5629
5679
(void )dispatch_assume_zero (kr );
5630
5680
}
5631
- dq -> do_ctxt = (void * )(uintptr_t )mp ;
5681
+ handle = mp ;
5682
+ #elif defined(__linux__ )
5683
+ int fd = eventfd (0 , EFD_CLOEXEC | EFD_NONBLOCK );
5684
+ if (fd == -1 ) {
5685
+ int err = errno ;
5686
+ switch (err ) {
5687
+ case EMFILE :
5688
+ DISPATCH_CLIENT_CRASH (err , "eventfd() failure: "
5689
+ "process is out of file descriptors" );
5690
+ break ;
5691
+ case ENFILE :
5692
+ DISPATCH_CLIENT_CRASH (err , "eventfd() failure: "
5693
+ "system is out of file descriptors" );
5694
+ break ;
5695
+ case ENOMEM :
5696
+ DISPATCH_CLIENT_CRASH (err , "eventfd() failure: "
5697
+ "kernel is out of memory" );
5698
+ break ;
5699
+ default :
5700
+ DISPATCH_INTERNAL_CRASH (err , "eventfd() failure" );
5701
+ break ;
5702
+ }
5703
+ }
5704
+ handle = fd ;
5705
+ #else
5706
+ #error "runloop support not implemented on this platform"
5707
+ #endif
5708
+ _dispatch_runloop_queue_set_handle (dq , handle );
5632
5709
5633
5710
_dispatch_program_is_probably_callback_driven = true;
5634
5711
}
5635
5712
5636
5713
static void
5637
- _dispatch_runloop_queue_port_dispose (dispatch_queue_t dq )
5714
+ _dispatch_runloop_queue_handle_dispose (dispatch_queue_t dq )
5638
5715
{
5639
- mach_port_t mp = ( mach_port_t ) dq -> do_ctxt ;
5640
- if (!mp ) {
5716
+ dispatch_runloop_handle_t handle = _dispatch_runloop_queue_get_handle ( dq ) ;
5717
+ if (!_dispatch_runloop_handle_is_valid ( handle ) ) {
5641
5718
return ;
5642
5719
}
5643
5720
dq -> do_ctxt = NULL ;
5721
+ #if TARGET_OS_MAC
5722
+ mach_port_t mp = handle ;
5644
5723
kern_return_t kr = mach_port_deallocate (mach_task_self (), mp );
5645
5724
DISPATCH_VERIFY_MIG (kr );
5646
5725
(void )dispatch_assume_zero (kr );
5647
5726
kr = mach_port_mod_refs (mach_task_self (), mp , MACH_PORT_RIGHT_RECEIVE , -1 );
5648
5727
DISPATCH_VERIFY_MIG (kr );
5649
5728
(void )dispatch_assume_zero (kr );
5729
+ #elif defined(__linux__ )
5730
+ int rc = close (handle );
5731
+ (void )dispatch_assume_zero (rc );
5732
+ #else
5733
+ #error "runloop support not implemented on this platform"
5734
+ #endif
5650
5735
}
5651
5736
5652
5737
#pragma mark -
5653
5738
#pragma mark dispatch_main_queue
5654
5739
5655
- mach_port_t
5656
- _dispatch_get_main_queue_port_4CF (void )
5740
+ dispatch_runloop_handle_t
5741
+ _dispatch_get_main_queue_handle_4CF (void )
5657
5742
{
5658
5743
dispatch_queue_t dq = & _dispatch_main_q ;
5659
- dispatch_once_f (& _dispatch_main_q_port_pred , dq ,
5660
- _dispatch_runloop_queue_port_init );
5661
- return (mach_port_t )dq -> do_ctxt ;
5744
+ dispatch_once_f (& _dispatch_main_q_handle_pred , dq ,
5745
+ _dispatch_runloop_queue_handle_init );
5746
+ return _dispatch_runloop_queue_get_handle (dq );
5747
+ }
5748
+
5749
+ #if TARGET_OS_MAC
5750
+ dispatch_runloop_handle_t
5751
+ _dispatch_get_main_queue_port_4CF (void )
5752
+ {
5753
+ return _dispatch_get_main_queue_handle_4CF ();
5662
5754
}
5755
+ #endif
5663
5756
5664
5757
static bool main_q_is_draining ;
5665
5758
@@ -5673,7 +5766,7 @@ _dispatch_queue_set_mainq_drain_state(bool arg)
5673
5766
}
5674
5767
5675
5768
void
5676
- _dispatch_main_queue_callback_4CF (mach_msg_header_t * msg DISPATCH_UNUSED )
5769
+ _dispatch_main_queue_callback_4CF (void * ignored DISPATCH_UNUSED )
5677
5770
{
5678
5771
if (main_q_is_draining ) {
5679
5772
return ;
@@ -5798,9 +5891,9 @@ _dispatch_queue_cleanup2(void)
5798
5891
#endif
5799
5892
5800
5893
#if DISPATCH_COCOA_COMPAT
5801
- dispatch_once_f (& _dispatch_main_q_port_pred , dq ,
5802
- _dispatch_runloop_queue_port_init );
5803
- _dispatch_runloop_queue_port_dispose (dq );
5894
+ dispatch_once_f (& _dispatch_main_q_handle_pred , dq ,
5895
+ _dispatch_runloop_queue_handle_init );
5896
+ _dispatch_runloop_queue_handle_dispose (dq );
5804
5897
#endif
5805
5898
}
5806
5899
0 commit comments