/*
    RMA memory malloc functions

    Copyright (C) 2000  Stefan Bellon

    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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#ifdef USE_RMA

#include <stdlib.h>
#include <string.h>
#include <kernel.h>
#include <swis.h>
#include "rma_malloc.h"

RMA_list_t *RMA_list = NULL;

void *RMA_untrapped_malloc(size_t size)
{
  _kernel_swi_regs reg;
  reg.r[0] = 6;
  reg.r[3] = (int) size;
  if (!_kernel_swi(OS_Module, &reg, &reg))
    return (void *) reg.r[2];
  else
    return NULL;
}

void RMA_untrapped_free(void *ptr)
{
  _kernel_swi_regs reg;
  reg.r[0] = 7;
  reg.r[2] = (int) ptr;
  _kernel_swi(OS_Module, &reg, &reg);
}

void *RMA_malloc(size_t size)
{
  void *block;
  RMA_list_t *temp = (RMA_list_t *) RMA_untrapped_malloc(sizeof(RMA_list_t));
  if (!temp)
    return NULL;
  block = RMA_untrapped_malloc(size);
  if (!block)
    return NULL;
  temp->block = block;
  temp->next = RMA_list;
  RMA_list = temp;
  return block;
}

void *RMA_calloc(size_t n, size_t size)
{
  void *block;
  RMA_list_t *temp = (RMA_list_t *) RMA_untrapped_malloc(sizeof(RMA_list_t));
  if (!temp)
    return NULL;
  block = RMA_untrapped_malloc(n * size);
  if (!block)
    return NULL;
  memset(block, 0, n * size);
  temp->block = block;
  temp->next = RMA_list;
  RMA_list = temp;
  return block;
}

void *RMA_realloc(void *ptr, size_t size)
{
  void *block;
  if (!ptr)
    return RMA_malloc(size);
  if (!size) {
    RMA_free(ptr);
    return NULL;
  }
  block = RMA_malloc(size);
  if (!block)
    return NULL;
  memmove(block, ptr, size);
  RMA_free(ptr);
  return block;
}

void RMA_free(void *ptr)
{
  RMA_list_t *iter, *old_iter;
  for (old_iter = iter = RMA_list; iter;
       old_iter = iter, iter = iter->next) {
    if (iter->block == ptr) {
      RMA_untrapped_free(ptr);
      if (RMA_list == iter) {
        RMA_list = iter->next;
        RMA_untrapped_free(iter);
        break;
      } else {
        old_iter = iter->next;
        RMA_untrapped_free(iter);
        break;
      }
    }
  }
}

void RMA_free_all(void)
{
  while (RMA_list)
    RMA_free(RMA_list->block);
}

#endif /* USE_RMA */
