/*
 * nasd_srpc_linux_alloc.c
 *
 * Allocate SRPC structures for linux kernel
 * We have to do something different than regular
 * NASD allocations here because we access this
 * memory in the socket callbacks, so it must
 * be nonpageable.
 *
 * Okay, I'm a psycho. This *is* in fact the generic
 * code, but I diddled nasd_linux_mem.h to do wired
 * allocations for me when I define NASD_LINUX_FORCE_NOPAGE
 * nonzero below. I feel unclean. --jimz
 *
 * Author: Jim Zelenka
 */
/*
 * Copyright (c) of Carnegie Mellon University, 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>
#define NASD_LINUX_FORCE_NOPAGE 1
#include <nasd/nasd_mem.h>
#include <nasd/nasd_freelist.h>
#include <nasd/nasd_srpc.h>

nasd_freelist_t *nasd_srpc_conn_freelist;
#define NASD_MAX_FREE_SRPC_CONN  16
#define NASD_SRPC_CONN_INC        2
#define NASD_SRPC_CONN_INITIAL    8

#define nasd_srpc_conn_free_fl(_conn_) \
  NASD_FREELIST_FREE_CLEAN(nasd_srpc_conn_freelist,_conn_,next,nasd_srpc_conn_clean)

#define nasd_srpc_conn_get_fl(_connp_) \
  NASD_FREELIST_GET_INIT(nasd_srpc_conn_freelist,_connp_,next,\
    (nasd_srpc_conn_t *),nasd_srpc_conn_init)

nasd_freelist_t *nasd_srpc_sock_freelist;
#define NASD_MAX_FREE_SRPC_SOCK  32
#define NASD_SRPC_SOCK_INC        2
#define NASD_SRPC_SOCK_INITIAL    8

#define nasd_srpc_sock_free_fl(_sock_) \
  NASD_FREELIST_FREE(nasd_srpc_sock_freelist,_sock_,next)

#define nasd_srpc_sock_get_fl(_sockp_) \
  NASD_FREELIST_GET(nasd_srpc_sock_freelist,_sockp_,next,(nasd_srpc_sock_t *))

nasd_freelist_t *nasd_srpc_call_freelist;
#define NASD_MAX_FREE_SRPC_CALL  64
#define NASD_SRPC_CALL_INC        2
#define NASD_SRPC_CALL_INITIAL    0

#define nasd_srpc_call_free_fl(_call_) \
  NASD_FREELIST_FREE_CLEAN(nasd_srpc_call_freelist,_call_,next,\
    nasd_srpc_call_clean)

#define nasd_srpc_call_get_fl(_callp_) \
  NASD_FREELIST_GET_INIT(nasd_srpc_call_freelist,_callp_,next,\
    (nasd_srpc_call_t *),nasd_srpc_call_init)

nasd_freelist_t *nasd_srpc_server_call_freelist;
#define NASD_MAX_FREE_SRPC_SERVER_CALL  64
#define NASD_SRPC_SERVER_CALL_INC        2
#define NASD_SRPC_SERVER_CALL_INITIAL    0

#define nasd_srpc_server_call_free_fl(_call_) \
  NASD_FREELIST_FREE_CLEAN(nasd_srpc_server_call_freelist,\
    _call_,next,nasd_srpc_server_call_clean)

#define nasd_srpc_server_call_get_fl(_callp_) \
  NASD_FREELIST_GET_INIT(nasd_srpc_server_call_freelist,\
    _callp_,next,(nasd_srpc_server_call_t *),\
    nasd_srpc_server_call_init)

void
nasd_srpc_conn_shutdown_freelist(
  void  *ignored)
{
  NASD_FREELIST_DESTROY_CLEAN(nasd_srpc_conn_freelist,next,
    (nasd_srpc_conn_t *),nasd_srpc_conn_clean);
}

void
nasd_srpc_sock_shutdown_freelist(
  void  *ignored)
{
  NASD_FREELIST_DESTROY(nasd_srpc_sock_freelist,next,(nasd_srpc_sock_t *));
}

void
nasd_srpc_call_shutdown_freelist(
  void  *ignored)
{
  NASD_FREELIST_DESTROY_CLEAN(nasd_srpc_call_freelist,next,
    (nasd_srpc_call_t *),nasd_srpc_call_clean);
}

void
nasd_srpc_server_call_shutdown_freelist(
  void  *ignored)
{
  NASD_FREELIST_DESTROY_CLEAN(nasd_srpc_server_call_freelist,next,
    (nasd_srpc_server_call_t *),nasd_srpc_server_call_clean);
}

nasd_status_t
nasd_srpc_sys_init(
  nasd_shutdown_list_t  *sl)
{
  nasd_status_t rc;

  NASD_FREELIST_CREATE(nasd_srpc_conn_freelist, NASD_MAX_FREE_SRPC_CONN,
    NASD_SRPC_CONN_INC, sizeof(nasd_srpc_conn_t));
  if (nasd_srpc_conn_freelist == NULL) {
    return(NASD_NO_MEM);
  }
  NASD_FREELIST_PRIME_INIT(nasd_srpc_conn_freelist, NASD_MAX_FREE_SRPC_CONN,next,
    (nasd_srpc_conn_t *), nasd_srpc_conn_init);
  rc = nasd_shutdown_proc(sl,
    nasd_srpc_conn_shutdown_freelist, NULL);
  if (rc) {
    nasd_srpc_conn_shutdown_freelist(NULL);
    return(rc);
  }

  NASD_FREELIST_CREATE(nasd_srpc_sock_freelist, NASD_MAX_FREE_SRPC_SOCK,
    NASD_SRPC_SOCK_INC, sizeof(nasd_srpc_sock_t));
  if (nasd_srpc_sock_freelist == NULL) {
    return(NASD_NO_MEM);
  }
  NASD_FREELIST_PRIME(nasd_srpc_sock_freelist, NASD_MAX_FREE_SRPC_SOCK,next,
    (nasd_srpc_sock_t *));
  rc = nasd_shutdown_proc(sl,
    nasd_srpc_sock_shutdown_freelist, NULL);
  if (rc) {
    nasd_srpc_sock_shutdown_freelist(NULL);
    return(rc);
  }

  NASD_FREELIST_CREATE(nasd_srpc_call_freelist,
    NASD_MAX_FREE_SRPC_CALL, NASD_SRPC_CALL_INC,
    sizeof(nasd_srpc_call_t));
  if (nasd_srpc_call_freelist == NULL)
    return(NASD_NO_MEM);
  rc = nasd_shutdown_proc(sl,
    nasd_srpc_call_shutdown_freelist, NULL);
  if (rc) {
    nasd_srpc_call_shutdown_freelist(NULL);
    return(rc);
  }

  NASD_FREELIST_CREATE(nasd_srpc_server_call_freelist,
    NASD_MAX_FREE_SRPC_SERVER_CALL, NASD_SRPC_SERVER_CALL_INC,
    sizeof(nasd_srpc_server_call_t));
  if (nasd_srpc_server_call_freelist == NULL)
    return(NASD_NO_MEM);
  rc = nasd_shutdown_proc(sl,
    nasd_srpc_server_call_shutdown_freelist, NULL);
  if (rc) {
    nasd_srpc_server_call_shutdown_freelist(NULL);
    return(rc);
  }

  return(NASD_SUCCESS);
}

nasd_status_t
nasd_srpc_conn_get(
  nasd_srpc_conn_t  **connp)
{
  nasd_srpc_conn_t *conn;

  nasd_srpc_conn_get_fl(conn);
  *connp = conn;
  if (conn == NULL)
    return(NASD_NO_MEM);

  nasd_srpc_conn_reinit(conn);

  return(NASD_SUCCESS);
}

void
nasd_srpc_conn_free(
  nasd_srpc_conn_t  *conn)
{
  nasd_srpc_conn_free_fl(conn);
}

nasd_status_t
nasd_srpc_sock_get(
  nasd_srpc_sock_t  **sockp)
{
  nasd_srpc_sock_t *s;
  nasd_status_t rc;

  nasd_srpc_sock_get_fl(s);
  if (s == NULL)
    return(NASD_NO_MEM);

  rc = nasd_srpc_sys_sock_init(s);
  if (rc) {
    nasd_srpc_sock_free_fl(s);
    return(rc);
  }

  *sockp = s;

  return(NASD_SUCCESS);
}

void
nasd_srpc_sock_free(
  nasd_srpc_sock_t  *sock)
{
  nasd_srpc_sock_free_fl(sock);
}

nasd_status_t
nasd_srpc_call_get(
  nasd_srpc_call_t  **callp)
{
  nasd_srpc_call_t *call;

  nasd_srpc_call_get_fl(call);
  if (call == NULL)
    return(NASD_NO_MEM);

  nasd_srpc_call_reinit(call);

  *callp = call;

  return(NASD_SUCCESS);
}

void
nasd_srpc_call_free(
  nasd_srpc_call_t  *call)
{
  NASD_ASSERT(call->ishashed == 0);
  nasd_srpc_call_free_fl(call);
}

nasd_status_t
nasd_srpc_server_call_get(
  nasd_srpc_server_call_t  **callp)
{
  nasd_srpc_server_call_t *call;

  nasd_srpc_server_call_get_fl(call);
  if (call == NULL)
    return(NASD_NO_MEM);

  nasd_srpc_server_call_reinit(call);

  *callp = call;

  return(NASD_SUCCESS);
}

void
nasd_srpc_server_call_free(
  nasd_srpc_server_call_t  *call)
{
  NASD_ASSERT(call->ishashed == 0);
  nasd_srpc_server_call_free_fl(call);
}

nasd_status_t
nasd_srpc_allocate_mem(
  void  **bufp,
  int     len)
{
  void *buf;

  NASD_Malloc(buf, len, (void *));
  if (buf == NULL) {
    *bufp = NULL;
    return(NASD_NO_MEM);
  }
  *bufp = buf;
  bzero((char *)buf, len);
  return(NASD_SUCCESS);
}

void
nasd_srpc_free_mem(
  void  *buf,
  int    len)
{
  NASD_Free(buf, len);
}

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