This is the 28th day of my participation in the August Challenge

NSConditionLock analysis

Compiled analysis created by NSConditionLock

NSConditionLock (conditionLock)

Resolution:

  • NSConditionLock *conditionLock = [[NSConditionLock alloc] initWithCondition:2];In the2Equivalent to oneMatching conditions; Set to2That is to saylockWhenConditionfor2The first execution of; So print it firstThread 2;
  • printThread 2And then, because of[conditionLock unlockWithCondition:1];Let’s change the match condition to1, so in execution1Conditional task, which is printingThread 1;
  • Due to the printThread 3The task is not setMatching conditions, is a normal lock, there is no condition control, so there is no need to match, will be executed first, printThread 3;
  • So the final result is printedThread 3.Thread 2.Thread 1Print in sequence;

At this time, we found that the execution of NSConditionLock is very similar to that of NSCondition, both of which have conditional control. So we have some questions, right?

  • NSConditionLockandNSConditionWhat does it matter
  • Conditions passed in during initialization2What is it?
  • lockWhenConditionHow do you do conditional control?
  • unlockWithConditionWhat did he do?

Now, let’s break each of these four points of doubt:

As a rule of thumb, if we want to investigate an initWithCondition:2 operation, we can add a symbol breakpoint for initWithCondition:

However, as we continue to execute the code, we find that the initWithCondition symbol breakpoint is not intercepted:

[NSConditionLock initWithCondition:] -[NSConditionLock initWithCondition:] -[NSConditionLock initWithCondition:]

Symbol breakpoint intercepted successfully! Let’s look at what happens in the register:

  • x0Is the default parameter, the receiver of the message:NSConditionLock;
  • x1Is the default parameter,SEL:initWithCondition:;
  • x2Is the parameter of the method:2;

Next, we analyze the execution process through assembly code. We can ignore the details. Then, we only need to pay attention to the execution of BL and RETURN instructions, because BL is a jump instruction, and there will be related processing, while return; The instruction returns directly; We put all on the bl instruction of breakpoints, and then continue to execute down, analysis NSConditionLock initWithCondition: method of implementation process:

Now an unknown object calls init and passes in parameter 2; [? init:2]

To continue:

The NSConditionLock object calls the init method and passes argument 2; -[NSConditionLock init:2]

To continue:

The NSConditionLock object calls the zone method; -[NSConditionLock zone]

To continue:

NSCondition calls allocWithZone:; +[NSCondition allocWithZone:]

To continue:

NSCondition calls init; -[NSCondition init]

To continue:

The return method is executed because the return value is placed in the X0 register; NSConditionLock (condition = 2);

-[NSConditionLock initWithCondition:] At this point, the clearing of memory and the handling of member variables are finished; We can look at the memory from the console:

  • 0x01000001ffe44209forisa;
  • <NSCondition: 0x28340c000>And the ones we saw created in the previous assemblyNSConditionAddress consistent;<NSCondition: 0x28340c000>Become the<NSConditionLock: 0x2808400f0>A member variable of;

If you do not see 2, you can continue to enlarge the view memory:

We see the address of 2;

-[NSConditionLock initWithCondition:]

  • 1.[? init:2]
  • 2,-[NSConditionLock init:2]
  • 3,-[NSConditionLock zone]
  • 4,+[NSCondition allocWithZone:]
  • 5,-[NSCondition init]

In -[NSConditionLock initWithCondition:], encapsulates an NSCondition

But how the lockWhenCondition and unlockWithCondition methods control is still unknown.

LockWhenCondition and unlockWithCondition analysis

Next, we analyze lockWhenCondition and unlockWithCondition, Add the symbol breakpoint -[NSConditionLock lockWhenCondition:] and -[NSConditionLock unlockWithCondition:]

LockWhenCondition analysis

Next, we still study the execution of BL instructions:

NSDate calls the distantFuture method;

Note that since we are multithreading, we need to pay attention to the Thread on the left. We are currently Thread 7, so we try to analyze in the current Thread and avoid analyzing the logic of other threads.

Continue to instruction B:

Call – [NSConditionLock lockWhenCondition: beforeDate:] method, this method has two parameters, means that we need to have a look at the x3 registers

From the name _NSConstantDateDistantFuture we speculate that the second parameter is extremely likely NSDate calls the distantFuture return values

We at this point, add symbols breakpoint – [NSConditionLock lockWhenCondition: beforeDate:], into this method:

The second argument is 1;

Continue with the next BL instruction:

The -[NSCondition Lock] method is called

Continue down (too many steps, similar analysis, we pick the main analysis) :

The -[NSCondition waitUntilDate] method is called to wait.

Then it will jump to another thread to do the operation, we won’t analyze this part; On coming back again:

The unlock method is called and returns 1, true; I will not wait now.

-[NSConditionLock lockWhenCondition]

  • 1.+[NSDate distantFuture]
  • 2,-[NSConditionLock lockWhenCondition:beforeDate:]
    • 2.1,-[NSCondition lock]
    • 2.2,-[NSCondition waitUntilDate]
    • 2.3,unlock

Next, unlockWithCondition;

UnlockWithCondition analysis

The -[NSCondition lock] method is called.

To continue:

The -[NSCondition broadcast] method is called.

Call -[NSCondition unlock]

-[NSConditionLock unlockWithCondition]

  • 1.-[NSCondition lock]
  • 2,-[NSCondition broadcast]
  • 3,-[NSCondition unlock]

Source contrast

Because we’re looking at the Swift version, the code is going to be a little different, so I’m going to comment the corresponding code directly in the code;

  • NSConditionLock initialization

  • lockWhenCondition

  • unlockWithCondition

By comparing the source code with the code logic we analyzed through assembly, basically the main process can be analyzed, which is one way we analyze the underlying source code: in the case of no open source, we can still roughly calculate the implementation logic of the underlying code through assembly;