blob: cab6fb9661303d2baf3e45e3730d262938882317 [file] [log] [blame]
/*
static char RCSId[] = "$Id$";
static char Copyright[] = "Copyright Robert J. Amstadt, 1994";
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "prototypes.h"
#include "heap.h"
#include "segmem.h"
#ifdef HAVE_IPC
static key_t MemoryKeys[SHMSEG]; /* Keep track of keys were using */
static int LinearInitialized = 0;
#endif
#ifdef HAVE_IPC
/**********************************************************************
* LinearFindSpace
*/
int
LinearFindSpace(int n_segments)
{
int i, n;
if (!LinearInitialized)
{
memset(MemoryKeys, -1, sizeof(MemoryKeys));
return 0;
}
for (i = 0, n = 0; i < SHMSEG, n != n_segments; i++)
{
if (MemoryKeys[i] < 0)
n++;
else
n = 0;
}
if (n != n_segments)
return -1;
else
return i - n;
}
#endif /* HAVE_IPC */
/**********************************************************************
* GlobalLinearLock
*
* OK, this is an evil beast. We will do one of two things:
*
* 1. If the data item <= 64k, then just call GlobalLock().
* 2. If the data item > 64k, then map memory.
*/
void *
GlobalLinearLock(unsigned int block)
{
GDESC *g, *g_first;
int loc_idx;
unsigned long addr;
int i;
/******************************************************************
* Get GDESC for this block.
*/
g_first = GlobalGetGDesc(block);
if (g_first == NULL)
return 0;
/******************************************************************
* Is block less then 64k in length?
*/
if (g_first->sequence != 1 || g_first->length == 1)
{
return (void *) GlobalLock(block);
}
/******************************************************************
* If there is already a linear lock on this memory, then
* just return a pointer to it.
*/
if (g_first->linear_count)
{
g_first->linear_count++;
return g_first->linear_addr;
}
/******************************************************************
* No luck. We need to do the linear mapping right now.
*/
#ifdef HAVE_IPC
loc_idx = LinearFindSpace(g_first->length);
if (loc_idx < 0)
return NULL;
addr = (unsigned long) SHM_RANGE_START + (0x10000 * loc_idx);
g = g_first;
for (i = loc_idx;
i < loc_idx + g_first->length;
i++, addr += 0x10000, g = g->next)
{
if ((MemoryKeys[i] = IPCCopySelector(g->handle >> 3, addr, 0)) < 0)
return NULL;
g->linear_addr = (void *) addr;
g->linear_count = 1;
}
#endif /* HAVE_IPC */
return g_first->linear_addr;
}
/**********************************************************************
* GlobalLinearUnlock
*
*/
unsigned int
GlobalLinearUnlock(unsigned int block)
{
GDESC *g, *g_first;
int loc_idx;
int i;
/******************************************************************
* Get GDESC for this block.
*/
g_first = GlobalGetGDesc(block);
if (g_first == NULL)
return block;
/******************************************************************
* Is block less then 64k in length?
*/
if (g_first->sequence != 1 || g_first->length == 1)
{
return GlobalUnlock(block);
}
/******************************************************************
* Make sure we have a lock on this block.
*/
#ifdef HAVE_IPC
if (g_first->linear_count > 1)
{
g_first->linear_count--;
}
else if (g_first->linear_count == 1)
{
g = g_first;
loc_idx = (((unsigned int) g_first - (unsigned int) SHM_RANGE_START)
/ 0x10000);
for (i = 0; i < g_first->length; i++, g = g->next)
{
shmdt(g->linear_addr);
g->linear_addr = NULL;
MemoryKeys[i] = -1;
}
g_first->linear_count = 0;
return 0;
}
#endif /* HAVE_IPC */
return 0;
}
/**********************************************************************/
void LinearTest()
{
#if 0
unsigned int handle;
int *seg_ptr;
int *lin_ptr;
int seg, i;
int *p;
handle = GlobalAlloc(0, 0x40000);
seg_ptr = GlobalLock(handle);
lin_ptr = GlobalLinearLock(handle);
for (seg = 0; seg < 4; seg++)
{
p = (int *) ((char *) seg_ptr + (0x80000 * seg));
for (i = 0; i < (0x10000 / sizeof(int)); i++, p++)
*p = (seg * (0x10000 / sizeof(int))) + i;
}
p = lin_ptr;
for (i = 0; i < (0x40000 / sizeof(int)); i++, p++)
{
if (*p != i)
printf("lin_ptr[%x] = %x\n", i, *p);
}
#endif
}