Repository: netty/netty
File: transport/src/main/java/io/netty/channel/ManualIoEventLoop.java (Java)

Code before:
    };
    private final BlockingIoHandlerContext blockingContext = new BlockingIoHandlerContext();
    private final Thread owningThread;
    private final IoHandler handler;

    private volatile long gracefulShutdownQuietPeriod;
    private volatile long gracefulShutdownTimeout;
    private long gracefulShutdownStartTime;
    private long lastExecutionTime;
    private boolean initialized;

    /**
     * Create a new {@link IoEventLoop} that is owned by the user and so needs to be driven by the user with the given
     * {@link Thread}. This means that the user is responsible to call either {@link #runNow()} or
     * {@link #run(long)} to execute IO or tasks that were submitted to this {@link IoEventLoop}.
     *
     * @param owningThread      the {@link Thread} that executes the IO and tasks for this {@link IoEventLoop}. The
     *                          user will use this {@link Thread} to call {@link #runNow()} or {@link #run(long)} to
     *                          make progress.
     * @param factory           the {@link IoHandlerFactory} that will be used to create the {@link IoHandler} that is
     *                          used by this {@link IoEventLoop}.
     */
    public ManualIoEventLoop(Thread owningThread, IoHandlerFactory factory) {
        this.owningThread = Objects.requireNonNull(owningThread, "owningThread");
        this.handler = factory.newHandler(this);
    }

    private int runAllTasks() {
        assert inEventLoop();
        int numRun = 0;
        boolean fetchedAll;
        do {
            fetchedAll = fetchFromScheduledTaskQueue(taskQueue);
            for (;;) {
                Runnable task = taskQueue.poll();
                if (task == null) {
                    break;
                }
                safeExecute(task);
                numRun++;
            }
        } while (!fetchedAll); // keep on processing until we fetched all scheduled tasks.
        if (numRun > 0) {
            lastExecutionTime = getCurrentTimeNanos();
        }
        return numRun;
    }

    private int run(IoHandlerContext context) {
        if (!initialized) {
            initialized = true;

Review comment (suggestion):
In theory we could make this happen once `run` is first started - but will still mess up with a wakeup happening right before the event loop's start (running on an external thread)

Code after:
    };
    private final BlockingIoHandlerContext blockingContext = new BlockingIoHandlerContext();
    private final Thread owningThread;
    private final IoHandler handler;

    private volatile long gracefulShutdownQuietPeriod;
    private volatile long gracefulShutdownTimeout;
    private long gracefulShutdownStartTime;
    private long lastExecutionTime;
    private boolean initialized;

    /**
     * Create a new {@link IoEventLoop} that is owned by the user and so needs to be driven by the user with the given
     * {@link Thread}. This means that the user is responsible to call either {@link #runNow()} or
     * {@link #run(long)} to execute IO or tasks that were submitted to this {@link IoEventLoop}.
     *
     * @param owningThread      the {@link Thread} that executes the IO and tasks for this {@link IoEventLoop}. The
     *                          user will use this {@link Thread} to call {@link #runNow()} or {@link #run(long)} to
     *                          make progress.
     * @param factory           the {@link IoHandlerFactory} that will be used to create the {@link IoHandler} that is
     *                          used by this {@link IoEventLoop}.
     */
    public ManualIoEventLoop(Thread owningThread, IoHandlerFactory factory) {
        this.owningThread = Objects.requireNonNull(owningThread, "owningThread");
        this.handler = factory.newHandler(this);
        state = new AtomicInteger(ST_STARTED);
    }

    private int runAllTasks() {
        assert inEventLoop();
        int numRun = 0;
        boolean fetchedAll;
        do {
            fetchedAll = fetchFromScheduledTaskQueue(taskQueue);
            for (;;) {
                Runnable task = taskQueue.poll();
                if (task == null) {
                    break;
                }
                safeExecute(task);
                numRun++;
            }
        } while (!fetchedAll); // keep on processing until we fetched all scheduled tasks.
        if (numRun > 0) {
            lastExecutionTime = getCurrentTimeNanos();
        }
        return numRun;
    }

    private int run(IoHandlerContext context) {
        if (!initialized) {