/*
    httperf -- a tool for measuring web server performance
    Copyright (C) 2000  Hewlett-Packard Company
    Contributed by David Mosberger-Tang <davidm@hpl.hp.com>

    This file is part of httperf, a web server performance measurment
    tool.

    This program 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 of the
    License, or (at your option) any later version.

    This program 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 this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA
*/

#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <httperf.h>
#include <call.h>
#include <conn.h>
#include <event.h>
#include <object.h>
#include <sess.h>

#define ALIGN(s)	(((s) + sizeof (double) - 1) & ~(sizeof (double) - 1))

static size_t type_size[OBJ_NUM_TYPES] =
  {
    ALIGN (sizeof (Conn)),
    ALIGN (sizeof (Call)),
    ALIGN (sizeof (Sess))
  };

struct free_list_el
  {
    struct free_list_el *next;
  };

static struct free_list_el *free_list[OBJ_NUM_TYPES];

static void
object_destroy (Object *obj)
{
  Object_Type type = obj->type;
  struct free_list_el *el;
  Event_Type event = 0;
  Any_Type arg;

  switch (type)
    {
    case OBJ_CALL:
      call_deinit ((Call *) obj);
      event = EV_CALL_DESTROYED;
      break;

    case OBJ_CONN:
      conn_deinit ((Conn *) obj);
      event = EV_CONN_DESTROYED;
      break;

    case OBJ_SESS:
      sess_deinit ((Sess *) obj);
      event = EV_SESS_DESTROYED;
      break;

    default:
      assert (0);
      break;
    }
  arg.l = 0;
  event_signal (event, obj, arg);

  /* Each object must be at least the size and alignment of "struct
     free_list_el".  Malloc takes care of returning properly aligned
     objects.  */
  el = (struct free_list_el *) obj;
  el->next = free_list[type];
  free_list[type] = el;
}

size_t
object_expand (Object_Type type, size_t size)
{
  size_t offset = type_size[type];
  type_size[type] += ALIGN (size);
  return offset;
}

Object *
object_new (Object_Type type)
{
  struct free_list_el *el;
  Event_Type event = 0;
  size_t obj_size;
  Any_Type arg;
  Object *obj;

  obj_size = type_size[type];

  if (free_list[type])
    {
      el = free_list[type];
      free_list[type] = el->next;
      obj = (Object *) el;
    }
  else
    {
      obj = malloc (obj_size);
      if (!obj)
	{
	  fprintf (stderr, "%s.object_new: %s\n", prog_name, strerror (errno));
	  return 0;
	}
    }
  memset (obj, 0, obj_size);
  obj->ref_count = 1;
  obj->type = type;
  switch (type)
    {
    case OBJ_CALL:
      call_init ((Call *) obj);
      event = EV_CALL_NEW;
      break;

    case OBJ_CONN:
      conn_init ((Conn *) obj);
      event = EV_CONN_NEW;
      break;

    case OBJ_SESS:
      sess_init ((Sess *) obj);
      event = EV_SESS_NEW;
      break;

    default:
      panic ("object_new: bad object type %d\n", type);
      break;
    }
  arg.l = 0;
  event_signal (event, obj, arg);
  return obj;
}

void
object_dec_ref (Object *obj)
{
  assert (obj->ref_count > 0);

  if (--obj->ref_count == 0)
    object_destroy (obj);
}


syntax highlighted by Code2HTML, v. 0.9.1