Example #1
0
File: test.c Project: 7heo/aports
int main(int argc, char **argv) {
    coro_create(&mainctx, NULL, NULL, NULL, 0);
    coro_stack_alloc(&stack, 0);
    coro_create(&ctx, coro_body, NULL, stack.sptr, stack.ssze);
    printf("Created a coro\n");
    coro_transfer(&mainctx, &ctx);
    printf("Back in main\n");
    coro_transfer(&mainctx, &ctx);
    printf("Back in main again\n");
    return 0;
}
Example #2
0
void coro_body(void *arg)
{
    int i = *(int*)arg;

    while(1) {
      count++;
      if(i == (INX - 1)) {
            coro_transfer(&ctx[i], &mainctx);
            continue;
      }
      coro_transfer(&ctx[i], &ctx[i+1]);
    }
}
Example #3
0
    void join() {
        if (!detached)
            return;

        #if defined(__APPLE__) || defined(__linux__)
            /* Release GIL and disassociate from thread state (which was originally
               associated with the main Python thread) */
            py::gil_scoped_release thread_state(true);

            coro_transfer(&ctx_main, &ctx_thread);
            coro_stack_free(&stack);

            /* Destroy the thread state that was created in mainloop() */
            {
                py::gil_scoped_acquire acquire;
                acquire.dec_ref();
            }
        #endif

        thread.join();
        detached = false;

        #if defined(__APPLE__) || defined(__linux__)
            /* Reacquire GIL and reassociate with thread state
               [via RAII destructor in 'thread_state'] */
        #endif
    }
Example #4
0
int main()
{
	coro_initialize();
	enum { STACKSIZE = 4096 };

	struct timeval tpend, tpstart;
	void* stack;
	stack = malloc(STACKSIZE);
	void* args = NULL;
	int count = 0;

	coro_create(testContext, test, args, stack, STACKSIZE);
	gettimeofday(&tpstart, 0);
	while(count++ < 1000000)
	{
		coro_transfer(mainContext, testContext);
	}
	gettimeofday(&tpend, 0);
	
	float timeuse = 1000000 * (tpend.tv_sec - tpstart.tv_sec) + tpend.tv_usec - tpstart.tv_usec; 
	timeuse /= 1000000; 
	printf("libcoro 切换1百万次耗时: %f 秒\n",timeuse); 

	free(stack);
//	printf("\nreturn to the main\n");
	return 0;
}
Example #5
0
int main(int argc, char **argv)
{
    long counter = atol(argv[1]);
    int stacksize = atoi(argv[2]);
    printf("total:%ld, stackszie:%dKB\n", counter, stacksize);

    coro_stack_alloc(&mainstack, stacksize*1024);
    coro_create(&mainctx, NULL, NULL, mainstack.sptr, mainstack.ssze);
    int i;    
    for(i=0; i<INX; i++) {
        index[i] = i;
        coro_stack_alloc(&stack[i], stacksize*1024);
        coro_create(&ctx[i], coro_body, &index[i], stack[i].sptr, stack[i].ssze);
    }

    while(1) {
        coro_transfer(&mainctx, &ctx[0]);
        count++;
        if(count > counter) {
            break;
        } 
    }
    printf("switch count:%ld\n", count); 
    return 0;
}
Example #6
0
void _swapFiber( Fiber *to, Fiber *from )
{
    assert( to->sptr );
    assert( from->sptr );

    coro_transfer( &to->coro_ctx, &from->coro_ctx );
}
Example #7
0
void cerl_callback test(void* args)
{
	for(;;)
	{
		//printf("\nthis is the test\n");
		coro_transfer(testContext, mainContext);
	}
}
Example #8
0
File: uvc.c Project: whtc123/libuvc
void uvc_switch(uvc_ctx *prev, uvc_ctx *next){
	printf("[switch]  %s  ->  %s\n", prev->name, next->name);
	uvc_thread_env *env = uvc_get_env();
	next->status = UVC_STATUS_RUNING;
	prev->status = UVC_STATUS_READY;
	env->runing_task = next;
	coro_transfer(&prev->cur, &next->cur);
}
Example #9
0
File: subreq.c Project: dimarik/ugh
void ugh_subreq_wait(ugh_client_t *c)
{
	if (0 < c->wait)
	{
		is_main_coro = 1;
		coro_transfer(&c->ctx, &ctx_main);
		is_main_coro = 0;
	}
}
Example #10
0
File: coro.c Project: kindy/libcoro
static void *
coro_init (void *args_)
{
  struct coro_init_args *args = (struct coro_init_args *)args_;
  coro_func func = args->func;
  void *arg = args->arg;

  coro_transfer (args->self, args->main);
  func (arg);

  return 0;
}
Example #11
0
static void
coro_init (void)
{
  volatile coro_func func = coro_init_func;
  volatile void *arg = coro_init_arg;

  coro_transfer (new_coro, create_coro);

#if __GCC_HAVE_DWARF2_CFI_ASM && __amd64
  asm (".cfi_undefined rip");
#endif

  func ((void *)arg);

  /* the new coro returned. bad. just abort() for now */
  abort ();
}
Example #12
0
static void *
coro_init (void *args_)
{
  struct coro_init_args *args = (struct coro_init_args *)args_;
  coro_func func = args->func;
  void *arg = args->arg;

  pthread_mutex_lock (&coro_mutex);

  /* we try to be good citizens and use deferred cancellation and cleanup handlers */
  pthread_cleanup_push (mutex_unlock_wrapper, &coro_mutex);
    coro_transfer (args->self, args->main);
    func (arg);
  pthread_cleanup_pop (1);

  return 0;
}
Example #13
0
void
coro_create (coro_context *ctx, coro_func coro, void *arg, void *sptr, size_t ssize)
{
  static coro_context nctx;
  static int once;

  if (!once)
    {
      once = 1;

      pthread_mutex_lock (&coro_mutex);
      pthread_cond_init (&nctx.cv, 0);
      null_tid = pthread_self ();
    }

  pthread_cond_init (&ctx->cv, 0);

  if (coro)
    {
      pthread_attr_t attr;
      struct coro_init_args args;

      args.func = coro;
      args.arg  = arg;
      args.self = ctx;
      args.main = &nctx;

      pthread_attr_init (&attr);
#if __UCLIBC__
      /* exists, but is borked */
      /*pthread_attr_setstacksize (&attr, (size_t)ssize);*/
#elif __CYGWIN__
      /* POSIX, not here */
      pthread_attr_setstacksize (&attr, (size_t)ssize);
#else
      pthread_attr_setstack (&attr, sptr, (size_t)ssize);
#endif
      pthread_attr_setscope (&attr, PTHREAD_SCOPE_PROCESS);
      pthread_create (&ctx->id, &attr, coro_init, &args);

      coro_transfer (args.main, args.self);
    }
  else
    ctx->id = null_tid;
}
Example #14
0
static
void ugh_client_wcb_recv(EV_P_ ev_io *w, int tev)
{
	int nb;
	ugh_client_t *c = aux_memberof(ugh_client_t, wev_recv, w);

	nb = aux_unix_recv(w->fd, c->buf_recv.data, c->buf_recv.size);
	log_debug("client recv: %d: %.*s", nb, nb, c->buf_recv.data);

	if (0 == nb)
	{
		ugh_client_del(c);
		return;
	}

	if (0 > nb)
	{
		if (EAGAIN == errno)
		{
			ev_timer_again(loop, &c->wev_timeout);
			return;
		}

		ugh_client_del(c);
		return;
	}

	c->buf_recv.data += nb;
	c->buf_recv.size -= nb;

	ev_timer_again(loop, &c->wev_timeout);

	if (NULL == c->request_end)
	{
		int status = ugh_parser_client(c, c->buf_recv.data - nb, nb);

		if (UGH_AGAIN == status)
		{
			return;
		}

		if (UGH_HTTP_BAD_REQUEST <= status)
		{
			ugh_client_send(c, status);
			return;
		}

		if (UGH_HTTP_POST == c->method)
		{
			ugh_header_t *hdr_content_length = ugh_client_header_get_nt(c, "Content-Length");

			if (0 != hdr_content_length->value.size)
			{
				c->content_length = atoi(hdr_content_length->value.data);

				if (c->content_length > (c->buf_recv.size + (c->buf_recv.data - c->request_end)))
				{
					c->body.data = aux_pool_nalloc(c->pool, c->content_length);
					c->body.size = c->buf_recv.data - c->request_end;

					memcpy(c->body.data, c->request_end, c->body.size);

					c->buf_recv.data = c->body.data + c->body.size;
					c->buf_recv.size = c->content_length - c->body.size;
				}
				else
				{
					c->body.data = c->request_end;
					c->body.size = c->buf_recv.data - c->request_end;
				}

				if (c->body.size < c->content_length)
				{
					return;
				}
			}
		}
	}
	else if (UGH_HTTP_POST == c->method)
	{
		c->body.size += nb;

		if (c->body.size < c->content_length)
		{
			return;
		}
	}

	ev_io_stop(loop, &c->wev_recv);
	ev_timer_stop(loop, &c->wev_timeout);

#if 1 /* prepare post args */
	ugh_header_t *hdr_content_type = ugh_client_header_get_nt(c, "Content-Type");

	if (sizeof("application/x-www-form-urlencoded") - 1 == hdr_content_type->value.size &&
		0 == strncmp(hdr_content_type->value.data, "application/x-www-form-urlencoded", hdr_content_type->value.size))
	{
		ugh_parser_client_body(c, c->body.data, c->body.size);
	}
#endif

#if 1 /* UGH_CORO ENABLE */
	c->stack = aux_pool_malloc(c->pool, UGH_CORO_STACK);

	if (NULL == c->stack)
	{
		ugh_client_send(c, UGH_HTTP_INTERNAL_SERVER_ERROR);
		return;
	}

	coro_create(&c->ctx, ugh_client_ccb_handle, c, c->stack, UGH_CORO_STACK, &ctx_main);
	is_main_coro = 0;
	coro_transfer(&ctx_main, &c->ctx);
	is_main_coro = 1;
#endif

#if 0 /* UGH_CORO DISABLE */
	ugh_client_ccb_handle(c);
#endif
}
Example #15
0
void
coro_create (coro_context *ctx, coro_func coro, void *arg, void *sptr, size_t ssize)
{
  coro_context nctx;
# if CORO_SJLJ
  stack_t ostk, nstk;
  struct sigaction osa, nsa;
  sigset_t nsig, osig;
# endif

  if (!coro)
    return;

  coro_init_func = coro;
  coro_init_arg  = arg;

  new_coro    = ctx;
  create_coro = &nctx;

# if CORO_SJLJ
  /* we use SIGUSR2. first block it, then fiddle with it. */

  sigemptyset (&nsig);
  sigaddset (&nsig, SIGUSR2);
  sigprocmask (SIG_BLOCK, &nsig, &osig);

  nsa.sa_handler = trampoline;
  sigemptyset (&nsa.sa_mask);
  nsa.sa_flags = SA_ONSTACK;

  if (sigaction (SIGUSR2, &nsa, &osa))
    {
      perror ("sigaction");
      abort ();
    }

  /* set the new stack */
  nstk.ss_sp    = STACK_ADJUST_PTR (sptr, ssize); /* yes, some platforms (IRIX) get this wrong. */
  nstk.ss_size  = STACK_ADJUST_SIZE (sptr, ssize);
  nstk.ss_flags = 0;

  if (sigaltstack (&nstk, &ostk) < 0)
    {
      perror ("sigaltstack");
      abort ();
    }

  trampoline_done = 0;
  kill (getpid (), SIGUSR2);
  sigfillset (&nsig); sigdelset (&nsig, SIGUSR2);

  while (!trampoline_done)
    sigsuspend (&nsig);

  sigaltstack (0, &nstk);
  nstk.ss_flags = SS_DISABLE;
  if (sigaltstack (&nstk, 0) < 0)
    perror ("sigaltstack");

  sigaltstack (0, &nstk);
  if (~nstk.ss_flags & SS_DISABLE)
    abort ();

  if (~ostk.ss_flags & SS_DISABLE)
    sigaltstack (&ostk, 0);

  sigaction (SIGUSR2, &osa, 0);
  sigprocmask (SIG_SETMASK, &osig, 0);

# elif CORO_LOSER

  coro_setjmp (ctx->env);
  #if __CYGWIN__ && __i386__
    ctx->env[8]                        = (long)    coro_init;
    ctx->env[7]                        = (long)    ((char *)sptr + ssize)         - sizeof (long);
  #elif __CYGWIN__ && __x86_64__
    ctx->env[7]                        = (long)    coro_init;
    ctx->env[6]                        = (long)    ((char *)sptr + ssize)         - sizeof (long);
  #elif defined __MINGW32__
    ctx->env[5]                        = (long)    coro_init;
    ctx->env[4]                        = (long)    ((char *)sptr + ssize)         - sizeof (long);
  #elif defined _M_IX86
    ((_JUMP_BUFFER *)&ctx->env)->Eip   = (long)    coro_init;
    ((_JUMP_BUFFER *)&ctx->env)->Esp   = (long)    STACK_ADJUST_PTR (sptr, ssize) - sizeof (long);
  #elif defined _M_AMD64
    ((_JUMP_BUFFER *)&ctx->env)->Rip   = (__int64) coro_init;
    ((_JUMP_BUFFER *)&ctx->env)->Rsp   = (__int64) STACK_ADJUST_PTR (sptr, ssize) - sizeof (__int64);
  #elif defined _M_IA64
    ((_JUMP_BUFFER *)&ctx->env)->StIIP = (__int64) coro_init;
    ((_JUMP_BUFFER *)&ctx->env)->IntSp = (__int64) STACK_ADJUST_PTR (sptr, ssize) - sizeof (__int64);
  #else
    #error "microsoft libc or architecture not supported"
  #endif

# elif CORO_LINUX

  coro_setjmp (ctx->env);
  #if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 0 && defined (JB_PC) && defined (JB_SP)
    ctx->env[0].__jmpbuf[JB_PC]        = (long)    coro_init;
    ctx->env[0].__jmpbuf[JB_SP]        = (long)    STACK_ADJUST_PTR (sptr, ssize) - sizeof (long);
  #elif __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 0 && defined (__mc68000__)
    ctx->env[0].__jmpbuf[0].__aregs[0] = (long int)coro_init;
    ctx->env[0].__jmpbuf[0].__sp       = (int *)   ((char *)sptr + ssize)         - sizeof (long);
  #elif defined (__GNU_LIBRARY__) && defined (__i386__)
    ctx->env[0].__jmpbuf[0].__pc       = (char *)  coro_init;
    ctx->env[0].__jmpbuf[0].__sp       = (void *)  ((char *)sptr + ssize)         - sizeof (long);
  #elif defined (__GNU_LIBRARY__) && defined (__x86_64__)
    ctx->env[0].__jmpbuf[JB_PC]        = (long)    coro_init;
    ctx->env[0].__jmpbuf[0].__sp       = (void *)  ((char *)sptr + ssize)         - sizeof (long);
  #else
    #error "linux libc or architecture not supported"
  #endif

# elif CORO_IRIX

  coro_setjmp (ctx->env, 0);
  ctx->env[JB_PC]                      = (__uint64_t)coro_init;
  ctx->env[JB_SP]                      = (__uint64_t)STACK_ADJUST_PTR (sptr, ssize) - sizeof (long);

# elif CORO_ASM

  #if __i386__ || __x86_64__
    ctx->sp = (void **)(ssize + (char *)sptr);
    *--ctx->sp = (void *)abort; /* needed for alignment only */
    *--ctx->sp = (void *)coro_init;
    #if CORO_WIN_TIB
      *--ctx->sp = 0;                    /* ExceptionList */
      *--ctx->sp = (char *)sptr + ssize; /* StackBase */
      *--ctx->sp = sptr;                 /* StackLimit */
    #endif
  #elif CORO_ARM
    /* return address stored in lr register, don't push anything */
  #else
    #error unsupported architecture
  #endif

  ctx->sp -= NUM_SAVED;
  memset (ctx->sp, 0, sizeof (*ctx->sp) * NUM_SAVED);

  #if __i386__ || __x86_64__
    /* done already */
  #elif CORO_ARM
    ctx->sp[0] = coro; /* r4 */
    ctx->sp[1] = arg;  /* r5 */
    ctx->sp[8] = (char *)coro_init; /* lr */
  #else
    #error unsupported architecture
  #endif

# elif CORO_UCONTEXT

  getcontext (&(ctx->uc));

  ctx->uc.uc_link           =  0;
  ctx->uc.uc_stack.ss_sp    = sptr;
  ctx->uc.uc_stack.ss_size  = (size_t)ssize;
  ctx->uc.uc_stack.ss_flags = 0;

  makecontext (&(ctx->uc), (void (*)())coro_init, 0);

# endif

  coro_transfer (create_coro, new_coro);
}
Example #16
0
File: test.c Project: 7heo/aports
void coro_body(void *arg) {
    printf("OK\n");
    coro_transfer(&ctx, &mainctx);
    printf("Back in coro\n");
    coro_transfer(&ctx, &mainctx);
}
Example #17
0
void coro_switch(coroutine *from, coroutine *to) {
    ASSERT(from); 
    ASSERT(to);
    coro_transfer(&from->ctx, &to->ctx);
}
Example #18
0
File: subreq.c Project: dimarik/ugh
int ugh_subreq_del(ugh_subreq_t *r, uint32_t ft_type, int ft_errno)
{
	ev_io_stop(loop, &r->wev_recv);
	ev_io_stop(loop, &r->wev_send);
	ev_io_stop(loop, &r->wev_connect);
	ev_timer_stop(loop, &r->wev_timeout);
	ev_timer_stop(loop, &r->wev_timeout_connect);

	close(r->wev_recv.fd);

	switch (ft_type)
	{
	case UGH_UPSTREAM_FT_ERROR:
		log_warn("connection or read/write error (%d: %s) on upstream socket (%.*s:%.*s%.*s%s%.*s, addr=%s:%u) while %.*s%s%.*s"
			, ft_errno
			, aux_strerror(ft_errno)
			, (int) r->u.host.size, r->u.host.data
			, (int) r->u.port.size, r->u.port.data
			, (int) r->u.uri.size, r->u.uri.data
			, r->u.args.size ? "?" : ""
			, (int) r->u.args.size, r->u.args.data
			, inet_ntoa(r->addr.sin_addr)
			, ntohs(r->addr.sin_port)
			, (int) r->c->uri.size, r->c->uri.data
			, r->c->args.size ? "?" : ""
			, (int) r->c->args.size, r->c->args.data
		);
		break;
	case UGH_UPSTREAM_FT_TIMEOUT:
		log_warn("upstream timeout (%.*s:%.*s%.*s%s%.*s, addr=%s:%u) while %.*s%s%.*s"
			, (int) r->u.host.size, r->u.host.data
			, (int) r->u.port.size, r->u.port.data
			, (int) r->u.uri.size, r->u.uri.data
			, r->u.args.size ? "?" : ""
			, (int) r->u.args.size, r->u.args.data
			, inet_ntoa(r->addr.sin_addr)
			, ntohs(r->addr.sin_port)
			, (int) r->c->uri.size, r->c->uri.data
			, r->c->args.size ? "?" : ""
			, (int) r->c->args.size, r->c->args.data
		);
		break;
	case UGH_UPSTREAM_FT_INVALID_HEADER:
		log_warn("invalid header in upstream response (%.*s:%.*s%.*s%s%.*s, addr=%s:%u) while %.*s%s%.*s"
			, (int) r->u.host.size, r->u.host.data
			, (int) r->u.port.size, r->u.port.data
			, (int) r->u.uri.size, r->u.uri.data
			, r->u.args.size ? "?" : ""
			, (int) r->u.args.size, r->u.args.data
			, inet_ntoa(r->addr.sin_addr)
			, ntohs(r->addr.sin_port)
			, (int) r->c->uri.size, r->c->uri.data
			, r->c->args.size ? "?" : ""
			, (int) r->c->args.size, r->c->args.data
		);
		break;
	case UGH_UPSTREAM_FT_HTTP_500:
	case UGH_UPSTREAM_FT_HTTP_502:
	case UGH_UPSTREAM_FT_HTTP_503:
	case UGH_UPSTREAM_FT_HTTP_504:
	case UGH_UPSTREAM_FT_HTTP_404:
	case UGH_UPSTREAM_FT_HTTP_5XX:
	case UGH_UPSTREAM_FT_HTTP_4XX:
		log_warn("error status %u in upstream response (%.*s:%.*s%.*s%s%.*s, addr=%s:%u) while %.*s%s%.*s"
			, r->status
			, (int) r->u.host.size, r->u.host.data
			, (int) r->u.port.size, r->u.port.data
			, (int) r->u.uri.size, r->u.uri.data
			, r->u.args.size ? "?" : ""
			, (int) r->u.args.size, r->u.args.data
			, inet_ntoa(r->addr.sin_addr)
			, ntohs(r->addr.sin_port)
			, (int) r->c->uri.size, r->c->uri.data
			, r->c->args.size ? "?" : ""
			, (int) r->c->args.size, r->c->args.data
		);
		break;
	case UGH_UPSTREAM_FT_TIMEOUT_CONNECT:
		log_warn("upstream connect timeout (%.*s:%.*s%.*s%s%.*s, addr=%s:%u) while %.*s%s%.*s"
			, (int) r->u.host.size, r->u.host.data
			, (int) r->u.port.size, r->u.port.data
			, (int) r->u.uri.size, r->u.uri.data
			, r->u.args.size ? "?" : ""
			, (int) r->u.args.size, r->u.args.data
			, inet_ntoa(r->addr.sin_addr)
			, ntohs(r->addr.sin_port)
			, (int) r->c->uri.size, r->c->uri.data
			, r->c->args.size ? "?" : ""
			, (int) r->c->args.size, r->c->args.data
		);
		break;
	}

	/* stop if full timeout is already ticked out */
	if (UGH_TIMEOUT_FULL == r->timeout_type && r->timeout < ev_now(loop) - r->response_time)
	{
		goto ok;
	}

	if (r->upstream && r->upstream_tries <= r->upstream->values_size
		&& (r->c->s->cfg->next_upstream & ft_type))
	{
		strp u_host;

		if (r->upstream_tries < r->upstream->values_size)
		{
			r->upstream_current += 1;

			/*
			 * XXX MEGA HACK for antmat, if upstream has choose random
			 * directive, we add additional (upstreams_count - 1) to current
			 * upstream to imitate choosing random upstream right after FIRST
			 * failure
			 */

			if (r->upstream->choose == UGH_UPSTREAM_CHOOSE_RANDOM && r->upstream_tries == 1)
			{
				r->upstream_current += aux_random() % (r->upstream->values_size - 1);
			}

			r->upstream_current %= r->upstream->values_size;
			r->upstream_tries++;

			r->addr.sin_family = AF_INET;
			r->addr.sin_port = htons(r->upstream->values[r->upstream_current].port);

			u_host = &r->upstream->values[r->upstream_current].host;
		}
		else if (0 < r->upstream->backup_values_size)
		{
			r->upstream->backup_values_curr += 1;
			r->upstream->backup_values_curr %= r->upstream->backup_values_size;
			r->upstream_tries++;

			r->addr.sin_family = AF_INET;
			r->addr.sin_port = htons(r->upstream->backup_values[r->upstream->backup_values_curr].port);

			u_host = &r->upstream->backup_values[r->upstream->backup_values_curr].host;
		}
		else
		{
			goto ok;
		}

		r->state = 0; /* XXX maybe here we should reinit the whole subreq structure? */

		r->body.data = NULL;
		r->body.size = 0;

		r->b_send.rpos = 0;
		r->b_send.wpos = 0;

		r->buf_recv.data = r->buf_recv_data;
		r->buf_recv.size = UGH_SUBREQ_BUF;

		ugh_subreq_gen(r, u_host);

		JudyLFreeArray(&r->headers_hash, PJE0);

		return ugh_resolver_addq(r->c->s->resolver, u_host->data, u_host->size, r->resolver_ctx);
	}

ok:

	r->ft_type = ft_type;
	r->response_time = ev_now(loop) - r->response_time;

	if (r->connection_time == 0)
	{
		r->connection_time = r->response_time;
	}

	if (/* NULL == r->handle &&*/ (r->flags & UGH_SUBREQ_WAIT))
	{
		r->c->wait--;

		/* We check is_main_coro here, because we could possibly call
		 * ugh_subreq_del from module coroutine (e.g. when IP-address of
		 * subrequest was definitely mallformed) and in this case we don't need
		 * to call coro_transfer
		 */
		if (0 == r->c->wait && is_main_coro)
		{
			is_main_coro = 0;
			coro_transfer(&ctx_main, &r->c->ctx);
			is_main_coro = 1;
		}

		/* coro_transfer(&ctx_main, &r->c->ctx); */
	}

	if ((r->flags & UGH_SUBREQ_PUSH))
	{
		ugh_header_t *h_content_type = ugh_subreq_header_get_nt(r, "Content-Type");
		ugh_channel_add_message(r->ch, &r->body, &h_content_type->value, r);
	}

	JudyLFreeArray(&r->headers_hash, PJE0);

	aux_pool_free(r->c->pool);

	return 0;
}