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

Code before:
        return promise;
    }

    @Override
    public boolean isCompatible(Class<? extends IoHandle> handleType) {
        return handler.isCompatible(handleType);
    }

    @Override
    public boolean isIoType(Class<? extends IoHandler> handlerType) {
        return handler.getClass().equals(handlerType);
    }

    @Override
    public boolean inEventLoop(Thread thread) {
        return this.owningThread == thread;
    }

    /**
     * Set the owning thread that will call {@link #run}. May only be called once, and only if the owning thread was
     * not set in the constructor already.
     *
     * @param owningThread The owning thread
     */
    public void setOwningThread(Thread owningThread) {
        if (this.owningThread != null) {
            throw new IllegalStateException("Owning thread already set");
        }
        this.owningThread = Objects.requireNonNull(owningThread, "owningThread");
    }

    private void shutdown0(long quietPeriod, long timeout, int shutdownState) {
        boolean inEventLoop = inEventLoop();
        boolean wakeup;
        int oldState;
        for (;;) {
            if (isShuttingDown()) {
                return;
            }
            int newState;
            wakeup = true;
            oldState = state.get();
            if (inEventLoop) {
                newState = shutdownState;
            } else if (oldState == ST_STARTED) {
                newState = shutdownState;
            } else {
                newState = oldState;
                wakeup = false;
            }


Review comment (suggestion):
Since the event loop check can still read it racily - we want to make sure that once set will be observed as set by everyone in the right order (i.e. first `null` than `non null` for everything) so I would make it a CAS.
I'm not a big fan of using concurrency if is not needed, but since external threads can call `ManualIoEventLoop::execute` before/after the value is set, we could make sure `Thread` is correctly published in few ways:
- `AtomicReferenceFieldUpdate::lazySet` on `setOwningThread` assuming single writer and multiple readers
- CAS assuming many writers (with one winning) and multiple readers
- plain set/get with some uncknown (which doesn't look scary at first look, TBH) consequences, unless an external thread is keep on calling execute in a loop and the null value is hoisted out - but that would die for OOM before, likely XD

Code after:
        channel.unsafe().register(this, promise);
        return promise;
    }

    @Override
    public boolean isCompatible(Class<? extends IoHandle> handleType) {
        return handler.isCompatible(handleType);
    }

    @Override
    public boolean isIoType(Class<? extends IoHandler> handlerType) {
        return handler.getClass().equals(handlerType);
    }

    @Override
    public boolean inEventLoop(Thread thread) {
        return this.owningThread.get() == thread;
    }

    /**
     * Set the owning thread that will call {@link #run}. May only be called once, and only if the owning thread was
     * not set in the constructor already.
     *
     * @param owningThread The owning thread
     */
    public void setOwningThread(Thread owningThread) {
        Objects.requireNonNull(owningThread, "owningThread");
        if (!this.owningThread.compareAndSet(null, owningThread)) {
            throw new IllegalStateException("Owning thread already set");
        }
    }

    private void shutdown0(long quietPeriod, long timeout, int shutdownState) {
        boolean inEventLoop = inEventLoop();
        boolean wakeup;
        int oldState;
        for (;;) {
            if (isShuttingDown()) {
                return;
            }
            int newState;
            wakeup = true;
            oldState = state.get();
            if (inEventLoop) {
                newState = shutdownState;
            } else if (oldState == ST_STARTED) {
                newState = shutdownState;
            } else {
                newState = oldState;
                wakeup = false;
            }