@Override
  public int execute(final long r, final long c) {

    if (r == 0) { // by worker init process
      NginxResponse resp = handleRequest(makeRequest(0, 0));
      if (resp != null
          && resp.type() == NginxResponse.TYPE_FAKE_ASYNC_TAG
          && resp.fetchStatus(200) != 200) {
        log.error("initialize error %s", resp);
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
      }
      return NGX_HTTP_OK;
    }

    final NginxRequest req = makeRequest(r, c);
    int phase = req.phase();

    if (workers == null) {
      NginxResponse resp = handleRequest(req);
      if (resp.type() == NginxResponse.TYPE_FAKE_ASYNC_TAG) {
        if (!req.isReleased()
            && !req.isHijacked()
            && (phase == -1
                || phase == NGX_HTTP_HEADER_FILTER_PHASE)) { // from content handler invoking
          ngx_http_clojure_mem_inc_req_count(r);
        }
        return NGX_DONE;
      }
      return handleResponse(req, resp);
    }

    // for safe access with another thread
    req.prefetchAll();

    if (phase == -1
        || phase == NGX_HTTP_HEADER_FILTER_PHASE) { // -1 means from content handler invoking
      ngx_http_clojure_mem_inc_req_count(r);
    }
    workers.submit(
        new Callable<NginxClojureRT.WorkerResponseContext>() {
          @Override
          public WorkerResponseContext call() throws Exception {
            NginxResponse resp = handleRequest(req);
            // let output chain built before entering the main thread
            return new WorkerResponseContext(resp, req);
          }
        });

    return NGX_DONE;
  }
    @SuppressWarnings("rawtypes")
    @Override
    public void run() throws SuspendExecution {
      try {
        response = request.handler().process(request);
      } catch (Throwable e) {
        response = buildUnhandledExceptionResponse(request, e);
        log.error("unhandled exception in coroutine", e);
      }

      if (Coroutine.getActiveCoroutine().getResumeCounter() != 1) {
        request.handler().completeAsyncResponse(request, response);
      }
    }
 public NginxUnhandledExceptionResponse(NginxRequest r, Throwable e) {
   this.err = e;
   this.r = r;
   if (r.isReleased()) {
     this.type = TYPE_FATAL;
   } else {
     this.type = TYPE_ERROR;
   }
 }
  @Override
  public <K, V> long prepareHeaders(
      NginxRequest req, long status, Collection<Map.Entry<K, V>> headers) {
    long r = req.nativeRequest();
    long pool = UNSAFE.getAddress(r + NGX_HTTP_CLOJURE_REQ_POOL_OFFSET);
    long headers_out = r + NGX_HTTP_CLOJURE_REQ_HEADERS_OUT_OFFSET;

    String contentType = null;
    String server = null;
    if (headers != null) {
      for (Map.Entry<?, ?> hen : headers) {
        Object nameObj = hen.getKey();
        Object val = hen.getValue();

        if (nameObj == null || val == null) {
          continue;
        }

        String name = normalizeHeaderName(nameObj);
        if (name == null || name.length() == 0) {
          continue;
        }

        NginxHeaderHolder pusher = fetchResponseHeaderPusher(name);
        if (pusher == RESP_CONTENT_TYPE_HOLDER) {
          if (val instanceof String) {
            contentType = (String) val;
          } else { // TODO:support another types

          }
        }
        pusher.push(headers_out, pool, val);
      }
    }

    if (contentType == null && status != NGX_HTTP_SWITCHING_PROTOCOLS) {
      ngx_http_set_content_type(r);
    } else {
      int contentTypeLen =
          pushNGXString(
              headers_out + NGX_HTTP_CLOJURE_HEADERSO_CONTENT_TYPE_OFFSET,
              contentType,
              DEFAULT_ENCODING,
              pool);
      // be friendly to gzip module
      pushNGXSizet(headers_out + NGX_HTTP_CLOJURE_HEADERSO_CONTENT_TYPE_LEN_OFFSET, contentTypeLen);
    }

    pushNGXInt(headers_out + NGX_HTTP_CLOJURE_HEADERSO_STATUS_OFFSET, (int) status);
    return r;
  }
  public static NginxResponse handleRequest(final NginxRequest req) {
    try {

      if (coroutineEnabled) {
        CoroutineRunner coroutineRunner = new CoroutineRunner(req);
        Coroutine coroutine = new Coroutine(coroutineRunner);
        coroutine.resume();
        if (coroutine.getState() == Coroutine.State.FINISHED) {
          return coroutineRunner.response;
        } else {
          return new NginxJavaResponse(req, Constants.ASYNC_TAG);
        }
      } else {
        return req.handler().process(req);
      }
    } catch (Throwable e) {
      log.error("server unhandled exception!", e);
      return buildUnhandledExceptionResponse(req, e);
    }
  }