class Async::Task

def stop(later = false)

@parameter later [Boolean] Whether to stop the task later, or immediately.

If `later` is false, it means that `stop` has been invoked directly. When `later` is true, it means that `stop` is invoked by `stop_children` or some other indirect mechanism. In that case, if we encounter the "current" fiber, we can't stop it right away, as it's currently performing `#stop`. Stopping it immediately would interrupt the current stop traversal, so we need to schedule the stop to occur later.

Stop the task and all of its children.
def stop(later = false)
	if self.stopped?
		# If the task is already stopped, a `stop` state transition re-enters the same state which is a no-op. However, we will also attempt to stop any running children too. This can happen if the children did not stop correctly the first time around. Doing this should probably be considered a bug, but it's better to be safe than sorry.
		return stopped!
	end
	
	# If we are deferring stop...
	if @defer_stop == false
		# Don't stop now... but update the state so we know we need to stop later.
		@defer_stop = true
		return false
	end
	
	# If the fiber is alive, we need to stop it:
	if @fiber&.alive?
		# As the task is now exiting, we want to ensure the event loop continues to execute until the task finishes.
		self.transient = false
		
		if self.current?
			# If the fiber is current, and later is `true`, we need to schedule the fiber to be stopped later, as it's currently invoking `stop`:
			if later
				# If the fiber is the current fiber and we want to stop it later, schedule it:
				Fiber.scheduler.push(Stop::Later.new(self))
			else
				# Otherwise, raise the exception directly:
				raise Stop, "Stopping current task!"
			end
		else
			# If the fiber is not curent, we can raise the exception directly:
			begin
				# There is a chance that this will stop the fiber that originally called stop. If that happens, the exception handling in `#stopped` will rescue the exception and re-raise it later.
				Fiber.scheduler.raise(@fiber, Stop)
			rescue FiberError => error
				# In some cases, this can cause a FiberError (it might be resumed already), so we schedule it to be stopped later:
				Fiber.scheduler.push(Stop::Later.new(self))
			end
		end
	else
		# We are not running, but children might be, so transition directly into stopped state:
		stop!
	end
end