/// <summary> /// Blocks the calling thread until the thread represented by this instance terminates, /// while continuing to perform standard COM and SendMessage pumping. /// </summary> /// <param name="thread">The thread to join.</param> public static void Join(Thread thread) { if (CoyoteRuntime.IsExecutionControlled) { if (ThreadTasks.TryGetValue(thread, out Task task)) { ControlledTask.Wait(task); thread.Join(); } } else { thread.Join(); } }
/// <summary> /// Blocks the calling thread until the thread represented by this instance terminates /// or the specified time elapses, while continuing to perform standard COM and SendMessage /// pumping. /// </summary> /// <param name="thread">The thread to join.</param> /// <param name="timeout"> /// A System.TimeSpan set to the amount of time to wait for the thread to terminate.</param> /// <returns> /// true if the thread terminated; false if the thread has not terminated after the /// amount of time specified by the timeout parameter has elapsed. /// </returns> public static bool Join(Thread thread, TimeSpan timeout) { if (CoyoteRuntime.IsExecutionControlled) { if (ThreadTasks.TryGetValue(thread, out Task task)) { ControlledTask.Wait(task, timeout); return(thread.Join(timeout)); } else { return(false); } } return(thread.Join(timeout)); }
/// <summary> /// Blocks the calling thread until the thread represented by this instance terminates /// or the specified time elapses, while continuing to perform standard COM and SendMessage /// pumping. /// </summary> /// <param name="thread">The thread to join.</param> /// <param name="millisecondsTimeout"> /// The number of milliseconds to wait for the thread to terminate.</param> /// <returns> /// true if the thread has terminated; false if the thread has not terminated after /// the amount of time specified by the millisecondsTimeout parameter has elapsed. /// </returns> public static bool Join(Thread thread, int millisecondsTimeout) { if (CoyoteRuntime.IsExecutionControlled) { if (ThreadTasks.TryGetValue(thread, out Task task)) { // TODO: support timeouts and cancellation tokens. ControlledTask.Wait(task, millisecondsTimeout); return(thread.Join(millisecondsTimeout)); } else { return(false); } } return(thread.Join(millisecondsTimeout)); }
/// <summary> /// Schedules a pulse operation that will either execute immediately or be scheduled /// to execute after the current owner releases the lock. This nondeterministic action /// is controlled by the runtime to simulate scenarios where the pulse is delayed by /// the operation system. /// </summary> private void SchedulePulse(PulseOperation pulseOperation) { var op = this.Resource.Runtime.GetExecutingOperation <AsyncOperation>(); if (this.Owner != op) { throw new SynchronizationLockException(); } // Pulse has a delay in the operating system, we can simulate that here // by scheduling the pulse operation to be executed nondeterministically. this.PulseQueue.Enqueue(pulseOperation); if (this.PulseQueue.Count is 1) { // Create a task for draining the queue. To optimize the testing performance, // we create and maintain a single task to perform this role. ControlledTask.Run(this.DrainPulseQueue); } }
/// <summary> /// Schedule a Coyote task to run the action. /// </summary> /// <param name="action">The action to schedule.</param> private static void ScheduleAction(Action action) { var task = ControlledTask.Run(action); ThreadTasks.TryAdd(Thread.CurrentThread, task); }