/*
 * srpc_test_ops.c
 *
 * RPC management for SRPC test server.
 *
 * Author: Jim Zelenka
 */
/*
 * Copyright (c) of Carnegie Mellon University, 1997,1998,1999.
 *
 * Permission to reproduce, use, and prepare derivative works of
 * this software for internal use is granted provided the copyright
 * and "No Warranty" statements are included with all reproductions
 * and derivative works. This software may also be redistributed
 * without charge provided that the copyright and "No Warranty"
 * statements are included in all redistributions.
 *
 * NO WARRANTY. THIS SOFTWARE IS FURNISHED ON AN "AS IS" BASIS.
 * CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER
 * EXPRESSED OR IMPLIED AS TO THE MATTER INCLUDING, BUT NOT LIMITED
 * TO: WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY
 * OF RESULTS OR RESULTS OBTAINED FROM USE OF THIS SOFTWARE. CARNEGIE
 * MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT
 * TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.
 */


#include <nasd/nasd_options.h>
#include <nasd/nasd_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_control.h>
#include <nasd/nasd_timer.h>
#include <nasd/nasd_marshall.h>
#include <nasd/nasd_timeout.h>

#include <nasd/nasd_pipe.h>

#include <sys/errno.h>

nasd_uint64 srpc_test_threads_in_rpc = 0;
int srpc_test_wait_shutdown = 0;
NASD_DECLARE_COND(srpc_test_shutdown_cond)
NASD_DECLARE_MUTEX(srpc_test_rpc_cnt_lock)
NASD_DECLARE_MUTEX(srpc_test_rpc_qdepth_lock)

int srpc_test_active = 0;

int srpc_test_rpc_qdepth = 0;
nasd_timer_t srpc_test_rpc_qdepth_timer;
srpc_test_rpc_opdepths_t srpc_test_rpc_opdepths;

nasd_uint64 srpc_test_shutdown_timeouts = 0;
nasd_timeout_handle_t srpc_test_shutdown_timeout_handle;

srpc_test_opstats_t srpc_test_opstats;
srpc_test_cachestats_t srpc_test_cache_stats;

nasd_timespec_t srpc_test_shutdown_timeout_interval = {1, 0};

void
srpc_test_begin_rpc(
  nasd_opstat_t  *opstat)
{
  NASD_ATOMIC_INC64(&srpc_test_threads_in_rpc);
}

void
srpc_test_end_rpc(
  nasd_opstat_t  *opstat)
{
  NASD_ATOMIC_DEC64(&srpc_test_threads_in_rpc);
  if (srpc_test_wait_shutdown && (srpc_test_threads_in_rpc == 0)) {
    NASD_BROADCAST_COND(srpc_test_shutdown_cond);
  }
}

void
srpc_test_dump_opstat(
  nasd_opstat_t  *os,
  char           *name)
{
  unsigned long s, ns;

  s = os->op_nsecs / 1000000000UL;
  ns = os->op_nsecs % 1000000000UL;
  nasd_printf("Operation: %s\n", name);
  nasd_printf("  time       %lu:%09lu\n", s, ns);
  nasd_printf("  num_ops    %5" NASD_64u_FMT "\n", os->num_ops);
  nasd_printf("  in_flight  %5" NASD_64u_FMT "\n", os->in_flight);
  nasd_printf("  invalid    %5" NASD_64u_FMT "\n", os->invalid);
}

#define DUMP_OPSTAT(_opname_) \
  srpc_test_dump_opstat(&srpc_test_opstats._opname_,NASD_STRING(_opname_))

#define SRPC_TEST_CSDUMP(_stat_) { \
  nasd_printf("  %24s %5lu\n", NASD_STRING(_stat_), srpc_test_cache_stats._stat_); \
}

void
srpc_test_timeout_shutdown_rpc(
  nasd_timeout_handle_t   tmh,
  void                   *arg1,
  void                   *arg2)
{
  nasd_timespec_t ts;
  char str[128];

#if SRPC_TEST_RPC_DEBUG_RPC_SHUTDOWN > 0
  nasd_gettime(&ts);
  nasd_printf("EDRFS: shutdown timeout at %s, srpc_test_threads_in_rpc=%"
    NASD_64u_FMT "\n", nasd_timestr_r(ts, str), srpc_test_threads_in_rpc);
#endif /* SRPC_TEST_RPC_DEBUG_RPC_SHUTDOWN > 0 */
  if (srpc_test_threads_in_rpc == 0) {
    NASD_BROADCAST_COND(srpc_test_shutdown_cond);
  }
  srpc_test_shutdown_timeouts++;
}

void
srpc_test_wait_shutdown_rpc()
{
  nasd_status_t rc;

  srpc_test_wait_shutdown = 1;

  rc = NASD_FAIL;

  NASD_LOCK_MUTEX(srpc_test_rpc_cnt_lock);
  while(srpc_test_threads_in_rpc) {
    if (rc) {
      rc = nasd_timeout_add(&srpc_test_shutdown_timeout_handle,
        srpc_test_timeout_shutdown_rpc, NULL, NULL,
        srpc_test_shutdown_timeout_interval,
        srpc_test_shutdown_timeout_interval,
        NASD_TIMEOUT_F_PERIODIC);
    }
    if (rc) {
      nasd_printf("SRPC test: got 0x%x (%s) adding timeout for shutdown-quiesce\n",
        rc, nasd_error_string(rc));
    }
    NASD_WAIT_COND(srpc_test_shutdown_cond,srpc_test_rpc_cnt_lock);
  }
  NASD_UNLOCK_MUTEX(srpc_test_rpc_cnt_lock);
}

void
srpc_test_shutdown_rpc(
  void  *ignored)
{
#if DEBUG_RPC_SHUTDOWN > 0
  nasd_printf("srpc_test_shutdown_rpc(): srpc_test_threads_in_rpc=%ld\n",
    srpc_test_threads_in_rpc);
#endif /* DEBUG_RPC_SHUTDOWN > 0 */
  srpc_test_wait_shutdown_rpc();

#if DUMP_OP_STATS > 0
  DUMP_OPSTAT(null);
  DUMP_OPSTAT(mount);
  DUMP_OPSTAT(fsstat);
  DUMP_OPSTAT(fsinfo);
  DUMP_OPSTAT(lookup);
  DUMP_OPSTAT(readdir);
  DUMP_OPSTAT(access);
  DUMP_OPSTAT(setattr);
  DUMP_OPSTAT(create);
  DUMP_OPSTAT(remove);
  DUMP_OPSTAT(mkdir);
  DUMP_OPSTAT(rmdir);
  DUMP_OPSTAT(newcookie);
  DUMP_OPSTAT(rename);
  DUMP_OPSTAT(getstats);
#endif /* DUMP_OP_STATS > 0 */
#if SRPC_TEST_DUMP_CACHE_STATS > 0
  SRPC_TEST_CSDUMP(dir_lookup);
  SRPC_TEST_CSDUMP(dir_force);
  SRPC_TEST_CSDUMP(dirc_load_attr);
  SRPC_TEST_CSDUMP(dirc_not_dir);
  SRPC_TEST_CSDUMP(dirc_load_dir);
  SRPC_TEST_CSDUMP(dirc_dirty);
  SRPC_TEST_CSDUMP(dirc_new_dirty);
  SRPC_TEST_CSDUMP(dirc_mkfree_loop);
  SRPC_TEST_CSDUMP(dirc_mkfree_wait);
  SRPC_TEST_CSDUMP(dir_load);
  SRPC_TEST_CSDUMP(post_attribute);
  SRPC_TEST_CSDUMP(post_attribute_valid);
  SRPC_TEST_CSDUMP(post_attribute_invalid);
  SRPC_TEST_CSDUMP(lookup_post_attribute);
  SRPC_TEST_CSDUMP(dir_writer_fls);
  SRPC_TEST_CSDUMP(dir_writer_pages);
  SRPC_TEST_CSDUMP(dir_load_attr);
  SRPC_TEST_CSDUMP(do_getattr);
  SRPC_TEST_CSDUMP(do_setattr);
  SRPC_TEST_CSDUMP(access_lookup_fail);
  SRPC_TEST_CSDUMP(access_not_dir);
  SRPC_TEST_CSDUMP(access_fault_attr);
  SRPC_TEST_CSDUMP(access_get_attr);
  SRPC_TEST_CSDUMP(lookup_get_attr);
  SRPC_TEST_CSDUMP(setattr_get_attr);
#endif /* SRPC_TEST_DUMP_CACHE_STATS > 0 */
}

nasd_status_t
srpc_test_rpc_init()
{
  nasd_status_t rc;

  srpc_test_rpc_qdepth = 0;

  bzero((char *)&srpc_test_opstats, sizeof(srpc_test_opstats));

  if (srpc_test_threads_in_rpc) {
    /* already/still running */
    return(NASD_FAIL);
  }

  srpc_test_wait_shutdown = 0;
  srpc_test_threads_in_rpc = 0;

  rc = nasd_cond_init(&srpc_test_shutdown_cond);
  if (rc)
    return(rc);
  rc = nasd_shutdown_cond(srpc_test_shutdown, &srpc_test_shutdown_cond);
  if (rc) {
    return(rc);
  }

  rc = nasd_mutex_init(&srpc_test_rpc_cnt_lock);
  if (rc)
    return(rc);
  rc = nasd_shutdown_mutex(srpc_test_shutdown, &srpc_test_rpc_cnt_lock);
  if (rc) {
    return(rc);
  }

  rc = nasd_mutex_init(&srpc_test_rpc_qdepth_lock);
  if (rc)
    return(rc);
  rc = nasd_shutdown_mutex(srpc_test_shutdown, &srpc_test_rpc_qdepth_lock);
  if (rc) {
    return(rc);
  }

  rc = srpc_test_rpc_specific_init();
  if (rc) {
    return(rc);
  }

  return(NASD_SUCCESS);
}

nasd_status_t
srpc_test_startup_rpc()
{
  nasd_status_t rc;

  rc = srpc_test_rpc_specific_startup();
  if (rc)
    return(rc);

#ifndef KERNEL
  rc = srpc_test_mq_specific_startup();
  if (rc)
    return rc;
#endif /* !KERNEL */

  rc = nasd_shutdown_proc(srpc_test_shutdown, srpc_test_shutdown_rpc, NULL);
  if (rc) {
    srpc_test_shutdown_rpc(NULL);
    return(rc);
  }

  srpc_test_active = 1;

  return(NASD_SUCCESS);
}

void
srpc_test_stop_rpc()
{
  srpc_test_rpc_specific_stop();
#ifndef KERNEL
  srpc_test_mq_specific_stop();
#endif /* !KERNEL */
}

nasd_status_t
srpc_test_rpc_listen(
  int          service_threads,
  nasd_uint16  ipport)
{
  nasd_status_t rc;

  rc = srpc_test_rpc_specific_listen(service_threads, ipport);

  return(rc);
}

nasd_status_t
srpc_test_rpc_set_stacksize(
  int  stacksize)
{
  nasd_status_t rc;

  rc = srpc_test_rpc_specific_set_stacksize(stacksize);

  return(rc);
}

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