// memman.cpp : Defines the entry point for the console application.
//

#include "kosSyst.h"
#include "mcsmemm.h"


void * __cdecl operator new ( size_t count, size_t element_size )
{
	return allocmem( (Dword)(count * element_size) );
}

void * __cdecl operator new [] ( size_t amount )
{
	return allocmem( (Dword)amount );
}

void * __cdecl operator new ( size_t amount )
{
	return allocmem( (Dword)amount );
}

void __cdecl operator delete ( void *pointer )
{
	if ( pointer != NULL ) freemem( pointer );
}

void __cdecl operator delete [] ( void *pointer )
{
	if ( pointer != NULL ) freemem( pointer );
}

Byte *allocmem( Dword reqsize )
{
	__asm
	{
		mov eax, 68
		mov ebx, 12
		mov ecx, reqsize
		int 0x40
	}

}

Dword freemem( void *vaddress )
{
	__asm
	{
		mov eax, 68
		mov ebx, 13
		mov ecx, vaddress
		int 0x40
	}

}
/*

//
Dword mmMutex = FALSE;
MemBlock *rootfree = NULL;
MemBlock *rootuser = NULL;
bool mmInitialized = false;
Byte *mmHeapTop = NULL;


//
Byte * AllocMemFromSystem( Dword reqSize )
{
	Byte *result;
	sProcessInfo pInfo;
	
	//
	if ( mmInitialized )
	{
		result = mmHeapTop;
	}
	else
	{
		//
		kos_ProcessInfo( &pInfo );
		//
		result = (Byte *)(pInfo.processInfo.used_memory + 1);
		//
		mmInitialized = true;
	}
	//
	if ( ! kos_ApplicationMemoryResize( ((Dword)result) + reqSize ) )
	{
		result = NULL;
	}
	//
	mmHeapTop = result + reqSize;
	//
	return result;
}


//
Byte *allocmem( Dword reqsize )
{
  MemBlock *BlockForCheck;
  MemBlock *LastKnownGood;
  Dword tail;
  Byte *address;

  //подровняем размер
  if( ( tail = reqsize % SIZE_ALIGN ) != 0 )
  {
    reqsize += SIZE_ALIGN - tail;
  }

  LastKnownGood = NULL;

  // ждём освобождения мьютекса
  while ( rtlInterlockedExchange( &mmMutex, TRUE ) )
  {
	  //
	  kos_Pause( 1 );
  }

  //ищем подходящий свободный блок
  if( rootfree != NULL )
  {
    for ( BlockForCheck = rootfree; ; BlockForCheck = BlockForCheck->Next )
    {
      if ( BlockForCheck->Size >= reqsize )
      {
        //нашли
        if ( LastKnownGood != NULL )
        {
          if ( LastKnownGood->Size >= BlockForCheck->Size )
            LastKnownGood = BlockForCheck;
        }
        else
          LastKnownGood = BlockForCheck;
        if ( LastKnownGood->Size == reqsize )
          break;
      }
      if ( BlockForCheck->Next == NULL )
        break;
    }
  }

  if ( LastKnownGood != NULL )
  {
    //проверим найденный блок на возможность деления
    tail = LastKnownGood->Size - reqsize;
    if ( tail >= ( sizeof(MemBlock) + SIZE_ALIGN ) )
    {
      //будем разбивать
      BlockForCheck = (MemBlock *)( ( (Byte *)LastKnownGood ) + tail );
      BlockForCheck->Size = reqsize;
      //вставим занятый блок в начало списка занатых блоков
      if( rootuser != NULL )
      {
        BlockForCheck->Next = rootuser;
        rootuser->Previous = BlockForCheck;
        BlockForCheck->Previous = NULL;
        rootuser = BlockForCheck;
      }
      else
      {
        rootuser = BlockForCheck;
        BlockForCheck->Next = NULL;
        BlockForCheck->Previous = NULL;
      }

      //изменим размер оставшейся части
      LastKnownGood->Size = tail - sizeof(MemBlock);
      address = ( (Byte *)BlockForCheck ) + sizeof(MemBlock);

	  // отпустим мьютекс
      rtlInterlockedExchange( &mmMutex, FALSE );

      return address;
    }
    else
    {
      //перемести блок из очереди свободных в начало очереди занятых
      //сначала выкинем его из очереди свободных
      if ( LastKnownGood->Previous != NULL )
      {
        LastKnownGood->Previous->Next = LastKnownGood->Next;
      }
      else
      {
        //блок стоит в начале очереди
        rootfree = LastKnownGood->Next;
      }
      if( LastKnownGood->Next != NULL )
      {
        LastKnownGood->Next->Previous = LastKnownGood->Previous;
      }
      //теперь вставим его в очередь занятых
      if( rootuser != NULL )
      {
        LastKnownGood->Next = rootuser;
        rootuser->Previous = LastKnownGood;
        LastKnownGood->Previous = NULL;
        rootuser = LastKnownGood;
      }
      else
      {
        rootuser = LastKnownGood;
        LastKnownGood->Next = NULL;
        LastKnownGood->Previous = NULL;
      }
	  //
      address = ( (Byte *)LastKnownGood ) + sizeof(MemBlock);

	  // отпустим мьютекс
      rtlInterlockedExchange( &mmMutex, FALSE );

      return address;
    }
  }
  else
  {
    //надо получить ещё кусочек памяти
    LastKnownGood = (MemBlock *)AllocMemFromSystem( reqsize + sizeof(MemBlock) );
	//
    if( LastKnownGood != NULL )
    {
      LastKnownGood->Size = reqsize;
      //теперь вставим его в очередь занятых
      if( rootuser != NULL )
      {
        LastKnownGood->Next = rootuser;
        rootuser->Previous = LastKnownGood;
        LastKnownGood->Previous = NULL;
        rootuser = LastKnownGood;
      }
      else
      {
        rootuser = LastKnownGood;
        LastKnownGood->Next = NULL;
        LastKnownGood->Previous = NULL;
      }
      address = ( (Byte *)LastKnownGood ) + sizeof(MemBlock);

	  // отпустим мьютекс
      rtlInterlockedExchange( &mmMutex, FALSE );

      return address;
    }
  }

  // отпустим мьютекс
  rtlInterlockedExchange( &mmMutex, FALSE );

  //
  rtlDebugOutString( "allocmem failed." );
  kos_ExitApp();
  //
  return NULL;
}

//
Dword freemem( void *vaddress )
{
  Dword result;

  Byte *checknext, *address = (Byte *)vaddress;
                               
  // ждём освобождения мьютекса
  while ( rtlInterlockedExchange( &mmMutex, TRUE ) )
  {
	  //
	  kos_Pause( 1 );
  }

  MemBlock *released = (MemBlock *)( address - sizeof(MemBlock) );

  result = released->Size;

  //убираем блок из списка занятых
  if ( released->Previous != NULL )
  {
    released->Previous->Next = released->Next;
  }
  else
  {
    rootuser = released->Next;
  }
  if ( released->Next != NULL )
  {
    released->Next->Previous = released->Previous;
  }
  //закинем теперь этот блок в список свободных
  released->Next = rootfree;
  released->Previous = NULL;
  rootfree = released;
  if ( released->Next != NULL )
  {
    released->Next->Previous = released;
  }

  //теперь поищем смежные свободные блоки
  checknext = (Byte *)(rootfree) + ( rootfree->Size + sizeof(MemBlock) );
  //
  for ( released = rootfree->Next; released != NULL; released = released->Next )
  {
    if ( checknext == (Byte *)released )
    {
      //собираем блоки вместе
      //сначала выкинем из очереди свободных
      released->Previous->Next = released->Next;
      if( released->Next != NULL )
      {
        released->Next->Previous = released->Previous;
      }
      //теперь увеличим размер корневого блока
      rootfree->Size += released->Size + sizeof(MemBlock);
      break;
    }
  }
  //если надо, поищем блоки перед текщим.
  checknext = (Byte *)(rootfree);
  //
  if ( released == NULL )
  {
    for ( released = rootfree->Next; released != NULL; released = released->Next )
    {
      if ( checknext == (Byte *)released + ( released->Size + sizeof(MemBlock) ) )
      {
        //собираем блоки вместе
        //увеличим размер блока
        released->Size += rootfree->Size + sizeof(MemBlock);
        //теперь выкинем из очереди свободных
        released->Previous->Next = released->Next;
        if ( released->Next != NULL )
        {
          released->Next->Previous = released->Previous;
        }
        //и закинем его в начало очереди вместо присоединённого блока из корня списка
        if ( rootfree->Next != NULL )
        {
          rootfree->Next->Previous = released;
        }
        released->Next = rootfree->Next;
        released->Previous = NULL;
        rootfree = released;
        break;
      }
    }
  }

  // отпустим мьютекс
  rtlInterlockedExchange( &mmMutex, FALSE );

  return result;
}

*/