code: private static void notifyListenerWithStackOverFlowProtection(final EventExecutor executor,
                                                                    final Future<?> future,
                                                                    final GenericFutureListener<?> listener) {
          if (executor.inEventLoop()) {
              final InternalThreadLocalMap threadLocals = InternalThreadLocalMap.get();
              final int stackDepth = threadLocals.futureListenerStackDepth();
              if (stackDepth < MAX_LISTENER_STACK_DEPTH) {
                  threadLocals.setFutureListenerStackDepth(stackDepth + 1);
                  try {
                      notifyListener0(future, listener);
                  } finally {
                      threadLocals.setFutureListenerStackDepth(stackDepth);
                  }
                  return;
              }
          }
  
          safeExecute(executor, new Runnable() {
              @Override
              public void run() {
                  notifyListener0(future, listener);
              }
          });
      }
docs: The logic in this method should be identical to {@link #notifyListeners()} but
  cannot share code because the listener(s) cannot be cached for an instance of {@link DefaultPromise} since the
  listener(s) may be changed and is protected by a synchronized operation.