/*
 * nasd_cheops_mgr_ops.c
 */
/*
 * Non-RPC-Specific Service Routines which invoke the RPC-specific ones
 */
/*
 * Copyright (c) 1996,1997,1998,1999 Carnegie Mellon University.
 * All rights reserved.
 *
 * Author: Sean Levy
 *
 * Permission to use, copy, modify and distribute this software and
 * its documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie Mellon the
 * rights to redistribute these changes.
 */

#include <nasd/nasd_options.h>
#include <nasd/nasd_types.h>
#include <nasd/nasd_cheops_types.h>
#include <nasd/nasd_freelist.h>
#include <nasd/nasd_itypes.h>
#include <nasd/nasd_mem.h>
#include <nasd/nasd_common.h>
#include <nasd/nasd_cheops_mgr.h>
#include <nasd/nasd_control.h>
#include <nasd/nasd_timer.h>
#include <nasd/nasd_marshall.h>
#include <nasd/nasd_cheops_rpc.h>
#include <nasd/nasd_timeout.h>
#include <sys/errno.h>

int nasd_cheops_mgr_wait_shutdown = 0;
NASD_DECLARE_COND(nasd_cheops_mgr_shutdown_cond);
NASD_DECLARE_MUTEX(nasd_cheops_mgr_rpc_cnt_lock);
nasd_uint64 nasd_cheops_mgr_threads_in_rpc = 0;
/*XXX Maybe later we can do per-op stats and queue depths, right now I just
  want it to work... This stuff is declared and initialized, but not
  actually used in the RPCs themselves.  SNL */
NASD_DECLARE_MUTEX(nasd_cheops_mgr_rpc_qdepth_lock);
int nasd_cheops_mgr_rpc_qdepth = 0;
nasd_timer_t nasd_cheops_mgr_qdepth_timer;
int nasd_cheops_mgr_active = 0;
nasd_uint16 nasd_cheops_mgr_shutdown_timeouts = 0;
nasd_timeout_handle_t nasd_cheops_mgr_shutdown_timeout_handle;
nasd_timespec_t nasd_cheops_mgr_shutdown_timeout_interval = {1, 0};
nasd_shutdown_list_t *nasd_cheops_mgr_shutdown_list = NULL;

nasd_status_t
nasd_cheops_mgr_really_shutdown(void)
{
  return NASD_SUCCESS;
}

void
nasd_cheops_mgr_begin_rpc(void)
{
  NASD_ATOMIC_INC64(&nasd_cheops_mgr_threads_in_rpc);
}

void
nasd_cheops_mgr_end_rpc(void)
{
  NASD_ATOMIC_DEC64(&nasd_cheops_mgr_threads_in_rpc);
  if (nasd_cheops_mgr_wait_shutdown && !nasd_cheops_mgr_threads_in_rpc) {
    NASD_BROADCAST_COND(nasd_cheops_mgr_shutdown_cond);
  }
}

void
nasd_cheops_mgr_timeout_shutdown_rpc(
  nasd_timeout_handle_t  tmh,
  void                  *arg1,
  void                  *arg2)
{
#if NASD_CHEOPS_MGR_RPC_DEBUG_RPC_SHUTDOWN > 0
  {
    nasd_timespec_t t;
    char str[128];

    nasd_gettime(&ts);
    nasd_printf("CHEOPS MGR: shutdown timeout at %s, "
                "nasd_cheops_mgr_threads_in_rpc=%" NASD_64u_FMT "\n",
                nasd_timestr_r(ts, str), nasd_cheops_mgr_threads_in_rpc);
  }
#endif /* NASD_CHEOPS_MGR_RPC_DEBUG_RPC_SHUTDOWN > 0 */
  if (!nasd_cheops_mgr_threads_in_rpc) {
    NASD_BROADCAST_COND(nasd_cheops_mgr_shutdown_cond);
  }
  nasd_cheops_mgr_shutdown_timeouts++;
}

void
nasd_cheops_mgr_wait_shutdown_rpc(void)
{
  nasd_status_t rc;

  nasd_cheops_mgr_wait_shutdown = 1;
  rc = NASD_FAIL;
  NASD_LOCK_MUTEX(nasd_cheops_mgr_rpc_cnt_lock);
  while (nasd_cheops_mgr_threads_in_rpc) {
    if (rc) {
      rc = nasd_timeout_add(&nasd_cheops_mgr_shutdown_timeout_handle,
                            nasd_cheops_mgr_timeout_shutdown_rpc, NULL, NULL,
                            nasd_cheops_mgr_shutdown_timeout_interval,
                            nasd_cheops_mgr_shutdown_timeout_interval,
                            NASD_TIMEOUT_F_PERIODIC);
    }
    if (rc) {
      nasd_printf("CHEOPS MGR: got 0x%x (%s) adding timeout for shutdown\n",
                  rc, nasd_error_string(rc));
    }
    NASD_WAIT_COND(nasd_cheops_mgr_shutdown_cond,nasd_cheops_mgr_rpc_cnt_lock);
  }
  NASD_UNLOCK_MUTEX(nasd_cheops_mgr_rpc_cnt_lock);
}

void
nasd_cheops_mgr_shutdown_rpc(
  void          *ignored)
{
#if DEBUG_RPC_SHUTDOWN > 0
  nasd_printf("nasd_cheops_mgr_shutdown_rpc(): "
              "nasd_cheops_mgr_threads_in_rpc=%" NASD_64u_FMT "\n",
              nasd_cheops_mgr_threads_in_rpc);
#endif /* DEBUG_RPC_SHUTDOWN > 0 */
  nasd_cheops_mgr_wait_shutdown_rpc();
}

nasd_status_t
nasd_cheops_mgr_rpc_init(void)
{
  nasd_status_t rc;

  nasd_cheops_mgr_rpc_qdepth = 0;
  if (nasd_cheops_mgr_threads_in_rpc)
    rc = NASD_FAIL;
  else {
    nasd_cheops_mgr_wait_shutdown = 0;
    rc = nasd_cond_init(&nasd_cheops_mgr_shutdown_cond);
    if (!rc) {
      rc = nasd_shutdown_list_init(&nasd_cheops_mgr_shutdown_list);
      if (!rc) {
        rc = nasd_shutdown_cond(nasd_cheops_mgr_shutdown_list,
                                &nasd_cheops_mgr_shutdown_cond);
        if (!rc) {
          rc = nasd_mutex_init(&nasd_cheops_mgr_rpc_cnt_lock);
          if (!rc) {
            rc = nasd_shutdown_mutex(nasd_cheops_mgr_shutdown_list,
                                     &nasd_cheops_mgr_rpc_cnt_lock);
            if (!rc) {
              rc = nasd_mutex_init(&nasd_cheops_mgr_rpc_qdepth_lock);
              if (!rc) {
                rc = nasd_shutdown_mutex(nasd_cheops_mgr_shutdown_list,
                                         &nasd_cheops_mgr_rpc_qdepth_lock);
                if (!rc)
                  rc = nasd_cheops_mgr_rpc_specific_init();
              }
            }
          }
        }
      }
    }
  }
  return rc;
}

nasd_status_t
nasd_cheops_mgr_startup_rpc(void)
{
  nasd_status_t rc;

  rc = nasd_cheops_mgr_rpc_init();
  if (!rc) {
    rc = nasd_cheops_mgr_rpc_specific_startup();
    if (!rc) {
      rc = nasd_shutdown_proc(nasd_cheops_mgr_shutdown_list,
                              nasd_cheops_mgr_shutdown_rpc, NULL);
      if (rc)
        nasd_cheops_mgr_shutdown_rpc(NULL);
      else {
        nasd_cheops_mgr_active = 1;
        rc = NASD_SUCCESS;
      }
    }
  }
  return rc;
}

void
nasd_cheops_mgr_stop_rpc(void)
{
  nasd_cheops_mgr_rpc_specific_stop();
}

nasd_status_t
nasd_cheops_mgr_rpc_listen(
  int           service_threads,
  nasd_uint16   port)
{
  return nasd_cheops_mgr_rpc_specific_listen(service_threads, port);
}

nasd_status_t
nasd_cheops_mgr_rpc_set_stacksize(
  int           stacksize)
{
  return nasd_cheops_mgr_rpc_specific_set_stacksize(stacksize);
}

/* Local Variables:  */
/* indent-tabs-mode: nil */
/* tab-width: 2 */
/* End: */
