This is the 14th day of my participation in the August More Text Challenge. For details, see: August More Text Challenge

In previous articles, we looked at functions and queues, and we looked at calling stacks of functions; Today we are going to analyze how deadlocks occur in synchronization functions.

Synchronization function deadlock

We will analyze the synchronization function from the entry point of dispatch_sync:

dispatch_sync

  • unlikelymeaningNot likely to happenIs generally considered to be followed by0; In this case it means_dispatch_block_has_private_data(work)The result returned by a function is usuallyfalse; About thisdc_flagsThe official explanation: ifdc_flagsLess than0x1000, the object iscontinue. Otherwise, the object has onePrivate layoutandMemory management Rules;
  • So what we should continue to analyze is_dispatch_sync_fMethod,dqThat’s where our function isThe queue, here forworkOne layer_dispatch_Block_invokeEncapsulation;workIs ourSynchronization functionperformThe callbackWhich is our specifictask;
  • DC_FLAG_BLOCKIs aMacro definition, its value is0x010ul;
  • The focus of our analysis should be ondqandworkOn;

_dispatch_sync_f

  • dqIs where our function isThe queue;
  • ctxtPointing to uswork“, which is specifically implementedtask;
  • funcRefers to the_dispatch_Block_invoke(work);
  • dc_flagsA value of0x010ul

_dispatch_sync_f_inline

  • likelyMeaning:Very often, very likely
  • dq_width == 1, which we analyzed in the last article,dq_width == 1Said that the currentThe queueIs aSerial queues;
  • _dispatch_barrier_sync_fproduceA deadlock;

_dispatch_barrier_sync_f

Continue with the call :_dispatch_barrier_sync_f_inline

_dispatch_barrier_sync_f_inline

  • _dispatch_sync_f_slowThis function should make an impression on us, as we demonstrated in the last articleA deadlock, the stack information in case of an exception is finally called_dispatch_sync_f_slow;

Note, however, that the _dispatch_sync_f_slow call does not report an error, and the final error is __DISPATCH_WAIT_FOR_QUEUE__:

  • A:

  • The simulator

_dispatch_sync_f_slow

  • __DISPATCH_WAIT_FOR_QUEUE__Is what ultimately leads toA deadlockAn error;

DISPATCH_WAIT_FOR_QUEUE

We see the same deadlock log message in this function as in the emulator:

So, further explaining that the simulator deadlock occurs here, let’s examine the conditions for the deadlock;

  • The queue of the synchronized function call is owned by the current thread.
  • _dq_state_drain_locked_by(dq_state, dsc->dsc_waiter): according to the_dispatch_sync_f_slowWe know the implementation of the functiondsc->dsc_waiterPoints to the_dispatch_tid_self()._dispatch_tid_self()Is the thread ID of the current queue thread:
#if TARGET_OS_MAC
#define _dispatch_tid_self()		((dispatch_tid)_dispatch_thread_port())
#elif defined(__linux__)
#define _dispatch_tid_self()        ((dispatch_tid)(_dispatch_get_tsd_base()->tid))
#elif defined(_WIN32)
#define _dispatch_tid_self()		((dispatch_tid)(_dispatch_get_tsd_base()->tid << 2))
Copy the code
  • dq_state: Indicates the status of the waiting queue

_dq_state_drain_locked_by

_dispatch_lock_is_locked_by

  • DLOCK_OWNER_MASKA value of#define DLOCK_OWNER_MASK ((dispatch_lock)0xfffffffc)Is a very large value
  • ((lock_value ^ tid) & DLOCK_OWNER_MASK)As long as(lock_value ^ tid)Don’t for0, the result must not be0So it’s obvious here(lock_value ^ tid)The results for0;(lock_value ^ tid)The results for0instructionslock_valuewithtidThe same;
  • This is the queue that is currently being calleddqIs currently theWait stateSo it happenedA deadlock;

conclusion

If the queue to be invoked is in the waiting state, then a deadlock occurs. Note that serial queue synchronization functions do not necessarily cause deadlocks;