/// <summary> /// Set the interrupt flag and release locks on resources if applicable. The coroutine /// is not terminated immediately but rather the next context-switch. Because of this, /// Executing Interrupt() does not mean that Completed is set to true immediately, and /// that the lock on the resource will be released. Note that it does not immediately /// release manually locked objects such as calling CoroutineMonitor.TryEnter within /// a coroutine. These objects will never be released. /// [TODO] Fixed this. /// </summary> public void Interrupt() { suspend = false; interrupt = true; // this should remove the resource lock if (mutex != null) { CoroutineMonitor.Exit(mutex); } }
// The coroutine that is started by Unity. This wraps the existing coroutine with // additional functions. IEnumerator _coroutine() { // Cache objects to avoid generating unnecessary rubbish. var waitToResume = new WaitWhile(isSuspended); if (mutex != null) { // wait to acquire the lock. if (!_single) { yield return(new WaitUntil(Function.delay(CoroutineMonitor.TryEnter, mutex))); } SetInUseBy(mutex, this); // it is possible for the suspend flag to be set before the coroutine even starts // executing, so we will have to pause the execution in such a situation. if (suspend) { yield return(waitToResume); } } // set the started status flag started = true; // this if statement is here because it is also possible for the coroutine to be // interrupted before execution, specifically while waiting for a lock on the mutex // in chained mode. If such a case happens, we do not want the user code to run at all. if (!interrupt) { while (routine.MoveNext()) { // Due to the syntax of iterators, assume that the user code is executed here. // The yield instruction for user code yield return(routine.Current); // Check if the suspend flag is set before running the next chunk of user code. if (suspend) { yield return(waitToResume); } // Check if the interrupt flag is set before running the next chunk of user // code. if (interrupt) { break; } } // guarantee execution of dispose block routine.Dispose(); } // Release the lock on the mutex if possible. Note that if the interrupt flag is set, // Then the Interrupt() function would have already released the lock, so we don't do // it twice. if (mutex != null && !interrupt) { CoroutineMonitor.Exit(mutex); } // Set the complete status flag. completed = true; }