// Copyright, 2001-2003, Astra Network Inc.  All Rights Reserved

// This source code has been published by Astra Network Inc. However, any
// use, reproduction, modification, distribution or transfer of this
// software, or any software which includes or is based upon any of this
// code, is only permitted if expressly authorized by a written license
// agreement from Astra. Contact your Astra representative directly for
// more information.
#include "sixfourbit.h"

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <string.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/mman.h>
#include <errno.h>

typedef struct sharedvar_data_s
{
  char name[PATH_MAX];		// name of shared memory region
  int64_t size;			// number of 64 bit integers that are shared
  int fd;			// fd to mmap shared memory
  int mutex_inited;
  pthread_mutex_t *mutex;
  int64_t *data;
}
sharedvar_data_t;



sharedvar_data_t *
sharedvar_create (char *name, int64_t size)
{
  sharedvar_data_t *blackbox;

  if (!(blackbox = (sharedvar_data_t *) malloc (sizeof (sharedvar_data_t))))
    {
      return NULL;
    }
  strncpy (blackbox->name, name, PATH_MAX);
  blackbox->name[PATH_MAX - 1] = '\0';
  blackbox->size = size;
  blackbox->fd = shm_open (blackbox->name, O_RDWR, 0777);
  if (blackbox->fd == -1)
    {
      free (blackbox);
      return NULL;
    }
  blackbox->mutex_inited = 0;
  if (ftruncate (blackbox->fd,
		 sizeof (pthread_mutex_t) +
		 blackbox->size * sizeof (int64_t)) == -1)
    {
      close (blackbox->fd);
      free (blackbox);
      return NULL;
    }
  blackbox->mutex = (pthread_mutex_t *) mmap (0,
					      sizeof (pthread_mutex_t) +
					      blackbox->size *
					      sizeof (int64_t),
					      PROT_READ | PROT_WRITE,
					      MAP_SHARED, blackbox->fd, 0);
  if (blackbox->mutex == MAP_FAILED)
    {
      close (blackbox->fd);
      free (blackbox);
      return NULL;
    }
  blackbox->data = (int64_t *) ((char *) blackbox->mutex +
				sizeof (pthread_mutex_t));

  while (pthread_mutex_lock (blackbox->mutex) != 0)
    ;				// spin on an invalid mutex? XXX - Fix me

  pthread_mutex_unlock (blackbox->mutex);

  return blackbox;
}

int
sharedvar_set (sharedvar_data_t * blackbox, int64_t offset, int64_t val)
{

  pthread_mutex_lock (blackbox->mutex);

  blackbox->data[offset] = val;
  //  fprintf( stderr, "sharedvar: set offset %ld, value %ld\n", offset, val );

  pthread_mutex_unlock (blackbox->mutex);

  return 0;
}

int64_t
sharedvar_get (sharedvar_data_t * blackbox, int64_t offset)
{
  int64_t val;
  pthread_mutex_lock (blackbox->mutex);

  val = blackbox->data[offset];
  // fprintf( stderr, "sharedvar: get offset %ld, value %ld\n", offset, val );
  pthread_mutex_unlock (blackbox->mutex);

  return val;
}

void
sharedvar_destroy (sharedvar_data_t * blackbox)
{
  munmap (blackbox->mutex,
	  sizeof (pthread_mutex_t) + blackbox->size * sizeof (int64_t));
  close (blackbox->fd);
  free (blackbox);
}
