2  * Copyright (c) 2008-2010 Apple Inc. All rights reserved. 
   4  * @APPLE_APACHE_LICENSE_HEADER_START@ 
   6  * Licensed under the Apache License, Version 2.0 (the "License"); 
   7  * you may not use this file except in compliance with the License. 
   8  * You may obtain a copy of the License at 
  10  *     http://www.apache.org/licenses/LICENSE-2.0 
  12  * Unless required by applicable law or agreed to in writing, software 
  13  * distributed under the License is distributed on an "AS IS" BASIS, 
  14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  15  * See the License for the specific language governing permissions and 
  16  * limitations under the License. 
  18  * @APPLE_APACHE_LICENSE_HEADER_END@ 
  24 dispatch_retain(dispatch_object_t dou
) 
  26         if (slowpath(dou
._do
->do_xref_cnt 
== DISPATCH_OBJECT_GLOBAL_REFCNT
)) { 
  27                 return; // global object 
  29         if (slowpath((dispatch_atomic_inc2o(dou
._do
, do_xref_cnt
) - 1) == 0)) { 
  30                 DISPATCH_CLIENT_CRASH("Resurrection of an object"); 
  35 _dispatch_retain(dispatch_object_t dou
) 
  37         if (slowpath(dou
._do
->do_ref_cnt 
== DISPATCH_OBJECT_GLOBAL_REFCNT
)) { 
  38                 return; // global object 
  40         if (slowpath((dispatch_atomic_inc2o(dou
._do
, do_ref_cnt
) - 1) == 0)) { 
  41                 DISPATCH_CLIENT_CRASH("Resurrection of an object"); 
  46 dispatch_release(dispatch_object_t dou
) 
  48         if (slowpath(dou
._do
->do_xref_cnt 
== DISPATCH_OBJECT_GLOBAL_REFCNT
)) { 
  52         unsigned int xref_cnt 
= dispatch_atomic_dec2o(dou
._do
, do_xref_cnt
) + 1; 
  53         if (fastpath(xref_cnt 
> 1)) { 
  56         if (fastpath(xref_cnt 
== 1)) { 
  57                 if (dou
._do
->do_vtable 
== (void*)&_dispatch_source_kevent_vtable
) { 
  58                         return _dispatch_source_xref_release(dou
._ds
); 
  60                 if (slowpath(DISPATCH_OBJECT_SUSPENDED(dou
._do
))) { 
  61                         // Arguments for and against this assert are within 6705399 
  62                         DISPATCH_CLIENT_CRASH("Release of a suspended object"); 
  64                 return _dispatch_release(dou
._do
); 
  66         DISPATCH_CLIENT_CRASH("Over-release of an object"); 
  70 _dispatch_dispose(dispatch_object_t dou
) 
  72         dispatch_queue_t tq 
= dou
._do
->do_targetq
; 
  73         dispatch_function_t func 
= dou
._do
->do_finalizer
; 
  74         void *ctxt 
= dou
._do
->do_ctxt
; 
  76         dou
._do
->do_vtable 
= (void *)0x200; 
  81                 dispatch_async_f(tq
, ctxt
, func
); 
  83         _dispatch_release(tq
); 
  87 _dispatch_release(dispatch_object_t dou
) 
  89         if (slowpath(dou
._do
->do_ref_cnt 
== DISPATCH_OBJECT_GLOBAL_REFCNT
)) { 
  90                 return; // global object 
  93         unsigned int ref_cnt 
= dispatch_atomic_dec2o(dou
._do
, do_ref_cnt
) + 1; 
  94         if (fastpath(ref_cnt 
> 1)) { 
  97         if (fastpath(ref_cnt 
== 1)) { 
  98                 if (slowpath(dou
._do
->do_next 
!= DISPATCH_OBJECT_LISTLESS
)) { 
  99                         DISPATCH_CRASH("release while enqueued"); 
 101                 if (slowpath(dou
._do
->do_xref_cnt
)) { 
 102                         DISPATCH_CRASH("release while external references exist"); 
 104                 return dx_dispose(dou
._do
); 
 106         DISPATCH_CRASH("over-release"); 
 110 dispatch_get_context(dispatch_object_t dou
) 
 112         return dou
._do
->do_ctxt
; 
 116 dispatch_set_context(dispatch_object_t dou
, void *context
) 
 118         if (dou
._do
->do_ref_cnt 
!= DISPATCH_OBJECT_GLOBAL_REFCNT
) { 
 119                 dou
._do
->do_ctxt 
= context
; 
 124 dispatch_set_finalizer_f(dispatch_object_t dou
, dispatch_function_t finalizer
) 
 126         dou
._do
->do_finalizer 
= finalizer
; 
 130 dispatch_suspend(dispatch_object_t dou
) 
 132         if (slowpath(dou
._do
->do_ref_cnt 
== DISPATCH_OBJECT_GLOBAL_REFCNT
)) { 
 135         // rdar://8181908 explains why we need to do an internal retain at every 
 137         (void)dispatch_atomic_add2o(dou
._do
, do_suspend_cnt
, 
 138                         DISPATCH_OBJECT_SUSPEND_INTERVAL
); 
 139         _dispatch_retain(dou
._do
); 
 144 _dispatch_resume_slow(dispatch_object_t dou
) 
 146         _dispatch_wakeup(dou
._do
); 
 147         // Balancing the retain() done in suspend() for rdar://8181908 
 148         _dispatch_release(dou
._do
); 
 152 dispatch_resume(dispatch_object_t dou
) 
 154         // Global objects cannot be suspended or resumed. This also has the 
 155         // side effect of saturating the suspend count of an object and 
 156         // guarding against resuming due to overflow. 
 157         if (slowpath(dou
._do
->do_ref_cnt 
== DISPATCH_OBJECT_GLOBAL_REFCNT
)) { 
 160         // Check the previous value of the suspend count. If the previous 
 161         // value was a single suspend interval, the object should be resumed. 
 162         // If the previous value was less than the suspend interval, the object 
 163         // has been over-resumed. 
 164         unsigned int suspend_cnt 
= dispatch_atomic_sub2o(dou
._do
, do_suspend_cnt
, 
 165                         DISPATCH_OBJECT_SUSPEND_INTERVAL
) + 
 166                         DISPATCH_OBJECT_SUSPEND_INTERVAL
; 
 167         if (fastpath(suspend_cnt 
> DISPATCH_OBJECT_SUSPEND_INTERVAL
)) { 
 168                 // Balancing the retain() done in suspend() for rdar://8181908 
 169                 return _dispatch_release(dou
._do
); 
 171         if (fastpath(suspend_cnt 
== DISPATCH_OBJECT_SUSPEND_INTERVAL
)) { 
 172                 return _dispatch_resume_slow(dou
); 
 174         DISPATCH_CLIENT_CRASH("Over-resume of an object"); 
 178 _dispatch_object_debug_attr(dispatch_object_t dou
, char* buf
, size_t bufsiz
) 
 180         return snprintf(buf
, bufsiz
, "xrefcnt = 0x%x, refcnt = 0x%x, " 
 181                         "suspend_cnt = 0x%x, locked = %d, ", dou
._do
->do_xref_cnt
, 
 183                         dou
._do
->do_suspend_cnt 
/ DISPATCH_OBJECT_SUSPEND_INTERVAL
, 
 184                         dou
._do
->do_suspend_cnt 
& 1);