/* rovm.c - ROVM Server 의 main 파일.
   Copyright (C) 2006 Weongyo Jeong (weongyo@gmail.com)

This file is part of ROVM.

ROVM is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.

ROVM is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING.  If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.  */

#include <stdlib.h>

#include "types.h"
#include "mpool.h"
#include "tktree.h"
#include "clstree.h"
#include "sha1.h"
#include "listen.h"
#include "rovm.h"

#include "thread.h"
#include "thread_mutex.h"
#include "thread_cond.h"

#include "mpm_worker_fdqueue.h"
#include "mpm_worker_pod.h"
#include "mpm_worker.h"

#include "connection.h"
#include "request.h"
#include "proc_rc.h"

#include "log.h"
#include "common.h"
#include "ticket.h"

#include "gc.h"

/**
   ROVM 의 중심적인 함수.  이 함수는 MPM 을 실행한다.

   @param r	ROVM 구조체.
*/
int
rovm_main (r)
     struct rovm *r;
{
  gc_run (r);

  mpm_pre_config (r);
  mpm_run (r);

  return 0;
}

/**
   Process 에 대한 정보를 가지는 구조체를 생성한다.

   @param argc	Argument Count
   @param argv	Argument Value 들
   @return	새롭게 생성된 struct process_rec 구조체를 반환한다.
 */
static struct process_rec *
create_process_rec (argc, argv)
     int argc;
     const char * const *argv;
{
  struct process_rec *process;
  rc_pool_t *cntx;
  rc_status_t stat;
  
  stat = mp_create (&cntx, NULL);
  if (stat != RC_SUCCESS)
    {
      /* XXX From the time that we took away the NULL pool->malloc mapping
	     we have been unable to log here without segfaulting.  */
      rovm_log (NULL, ROVMLOG_ERR, ROVMLOG_MARK,
		"rc_pool_create() failed to create initial context");
      rc_terminate ();
      exit (1);
    }

  mp_tag (cntx, "process");
  
  process = mp_alloc (cntx, sizeof (struct process_rec));
  process->pool = cntx;
  
  mp_create (&process->pconf, process->pool);
  mp_tag (process->pconf, "pconf");
  process->argc = argc;
  process->argv = argv;
  process->short_name = rc_filepath_name_get (argv[0]);

  return process;
}

/**
   ROVM Server 의 현재 상태를 초기화합니다.

   @param r	ROVM 구조체
   @param p	메모리 pool
 */
int
init_rovm_status (r, p)
     struct rovm *r;
     rc_pool_t *p;
{
  struct rovm_status *rs;

  rs = (struct rovm_status *) mp_alloc (p, sizeof (struct rovm_status));
  if (!rs)
    return -1;

  STATUS_SHUTDOWN_PENDING (rs) = 0;
  STATUS_RESTART_PENDING (rs) = 0;

  ROVM_STATUS (r) = rs;

  return 0;
}

/**
   Multi-Process 로 작동중일 경우, 효과적으로 자식 프로세스들을 다루기
   위해서 아래와 같이 scoreboard 라는 것을 사용합니다.  이를 초기화하는
   함수입니다.

   @param r     ROVM 구조체
   @param p     사용할 메모리 pool.
   @return      실패시 -1, 성공시 0
 */
int
init_rovm_sb (r, p)
     struct rovm *r;
     rc_pool_t *p;
{
  struct rovm_scoreboard *sb;

  sb = (struct rovm_scoreboard *) mp_calloc (p, sizeof (struct rovm_scoreboard));
  SB_PARENT (sb) = mp_calloc (p, CONF_DAEMONS_TO_START (ROVM_CONF (r)) * sizeof (struct process_score));
  
  ROVM_SCOREBOARD (r) =  sb;

  return 0;
}

/**
   ROVM 과 관련된 설정 파일을 초기화한다.

   @param r	ROVM 구조체
   @param p	메모리 pool
 */
int
init_rovm_config (r, p)
     struct rovm *r;
     rc_pool_t *p;
{
#define DEFAULT_LISTENBACKLOG 511
  struct rovm_config *c;

  c = (struct rovm_config *) mp_calloc (p, sizeof (struct rovm_config));
  if (!c)
    return -1;

  CONF_OPTION (c) |= OPTION_LOG_DEBUG_MESSAGES;

  /* 현재 ROVM 의 경우, debugging 모드와 일반 모드로 구분할 수 있습니다.  
     아래의 값을 0 으로 설정할 경우 일반 모드로 작동하게 되며, 1 로 설정할 경우
     debugging 모드로 작동하게 됩니다.  
     
     일반 모드의 경우, daemon 으로 설정하는 방법이 있으며, foreground 로 
     실행하는 방법이 존재합니다.  */
  CONF_ONE_PROCESS (c) = 1;
  /* 만약 daemon 으로 실행하기 원한다면 아래의 값을 0 으로 설정하고, foreground
     로 실행하길 원한다면 1 로 설정하시기 바랍니다.  */
  CONF_NO_DETACH (c) = 0;

  CONF_PORT (c) = DEFAULT_ROVM_LISTENING_PORT;

  /* Multi-Process 를 이용한 서비스를 실시할 경우, 아래의 숫자를 늘릴 수
     있을 것이다.  하지만 현재 ROVM 서버의 구조적인 문제로 반드시 아래의 두
     값은 1 이여야만 한다.  */
  CONF_DAEMONS_TO_START (c) = 1;
  CONF_DAEMONS_LIMIT (c) = 1;

  /* 하나의 Process 당 생성할 thread 의 최대 갯수를 정하는 부분입니다.  현재
     값으로 5 가 기본값으로 설정되어 있으며, 1 개의 listener 쓰레드와 5 개의
     worker 쓰레드가 생성되게 됩니다.  */
  CONF_THREADS_PER_CHILD (c) = 5;

  /* Listening 관련 변수들  */
  CONF_SEND_BUFFER_SIZE (c) = 0;        /* 시스템 default 값을 사용하기 위해서는 0 으로 설정해야 한다.  */
  CONF_RECEIVE_BUFFER_SIZE (c) = 0;     /* 시스템 default 값을 사용하기 위해서는 0 으로 설정해야 한다.  */
  CONF_LISTENBACKLOG (c) = DEFAULT_LISTENBACKLOG;

  /* ERROR 발생시 출력할 파일 descriptor 를 정할 수 있습니다.  현재로써는
     편리한 debugging 목적으로 stderr 로 출력되도록 설정되어 있습니다.  */
  CONF_ERROR_LOG (c) = stderr;
  CONF_LOGLEVEL (c) = DEFAULT_LOGLEVEL;

  /* Ticket 구조체가 기본값으로 가질 stack slot 의 갯수를 정하는 
     부분입니다.  기본적으로 DEFAULT_STACK_SLOT 값을 가지게 되어 있습니다. */
  CONF_DEFAULT_STACK_SLOT (c) = DEFAULT_STACK_SLOT;

  /* Class 파일들의 root 경로를 정하게 됩니다.  이 경로와 
     e://<hostname>[:<port>]<path> URL 의 <path> 가 결합하여 하나의 시스템
     경로를 가르키게 됩니다.

     (20050205) 현재 ROVM Server 의 경우, 설정 파일이 존재하지 않기 때문에
     사용자가 `NEW' Opcode 를 테스트하기 위해서는 이 부분을 적절히 수정하도록
     안내를 해줘야 할것입니다.  */
  CONF_CLASSROOT (c) = "/usr/local/rovm/classroot";

  ROVM_CONF (r) = c;

  return 0;
}

/**
   ROVM 에 필요한 초기화를 실행합니다.

   @return	초기화된 struct rovm * 을 반환합니다.
*/
struct rovm *
init_rovm (argc, argv)
     int argc;
     char *argv[];
{
  rc_status_t rv;
  struct rovm *r;
  struct process_rec *p;

  rc_initialize ();

  p = create_process_rec (argc, argv);

  r = (struct rovm *) mp_calloc (PROCREC_POOL (p), sizeof (struct rovm));
  if (!r)
    return NULL;

  ROVM_PROCESS (r) = p;

  rv = rc_thread_mutex_create (&ROVM_MUTEX (r), RC_THREAD_MUTEX_DEFAULT, PROCREC_POOL (p));
  if (rv != RC_SUCCESS)
    return NULL;
  
  /* Ticket TREE 를 초기화한다.  */
  if (init_rovm_tktree (r))
    return NULL;
  /* Class TREE 를 초기화합니다.  */
  if (init_rovm_clstree (r))
    return NULL;
  /* ROVM Configuration 관련 부분을 설정한다.  */
  if (init_rovm_config (r, PROCREC_POOL (p)))
    return NULL;
  /* ROVM Server 의 상태 정보를 초기화합니다.  */
  if (init_rovm_status (r, PROCREC_POOL (p)))
    return NULL;
  if (init_rovm_sb (r, PROCREC_POOL (p)))
    return NULL;
  /* Listening Socket 에 대한 초기화를 실시합니다.  */
  if (init_rovm_listen (r, PROCREC_POOL (p)))
    return NULL;
  /* Garbage Collector 에 대한 초기화를 실시합니다.  */
  if (init_rovm_gc (r, PROCREC_POOL (p)))
    return NULL;

  return r;
}

/**
   ROVM 을 마무리합니다. 

   @param r	ROVM 의 여러 정보를 가지는 구조체.
 */
int
finish_rovm (r)
     struct rovm *r;
{
  rc_terminate ();

  return 0;
}

/**
   ROVM 의 main 함수.
 */
int
main (argc, argv)
     int argc;
     char *argv[];
{
  struct rovm *r;

  r = init_rovm (argc, argv);
  if (!r)
    return -1;

  rovm_main (r);

  finish_rovm (r);

  return 0;
}
