📄 memblk.c
字号:
*****************************************************************************/
ULONG
pt_create( char name[4], void *paddr, void *laddr, ULONG length,
ULONG bsize, ULONG flags, ULONG *ptid, ULONG *nbuf )
{
p2pt_prtn_t *prtn;
ULONG error;
int i;
error = ERR_NO_ERROR;
/*
** First allocate memory for the partition control block.
*/
prtn = (p2pt_prtn_t *)ts_malloc( sizeof( p2pt_prtn_t ) );
if ( prtn != (p2pt_prtn_t *)NULL )
{
/*
** Ok... got a control block.
** Prepare to allocate and init the first partition data extent.
*/
/*
** Total number of used data blocks in partition
*/
prtn->used_blk_count = 0L;
/*
** Pointer to data extent for partition
*/
prtn->data_extent = (prtn_extent_t *)NULL;
/*
** Total data blocks per memory allocation block (extent)
*/
if ( (bsize % 2) || (bsize < 4) )
error = ERR_BUFSIZE;
prtn->blk_size = bsize;
if ( new_extent_for( prtn, paddr, (length / bsize) ) !=
(prtn_extent_t *)NULL )
{
/*
** ID for partition
*/
prtn->prtn_id = new_prtn_id();
/*
** Name for partition
*/
for ( i = 0; i < 4; i++ )
prtn->ptname[i] = name[i];
/*
** Option Flags for partition
*/
prtn->flags = flags;
/*
** Mutex for partition get/release block
*/
pthread_mutex_init( &(prtn->prtn_lock),
(pthread_mutexattr_t *)NULL );
/*
** If no errors thus far, we have a new partition ready to link
** into the partition list.
*/
if ( error == ERR_NO_ERROR )
{
/*
** Partition is linked by the acsending sequence of prtn_id.
*/
link_pcb( prtn );
/*
** Return the partition ID into the caller's storage location.
*/
if ( ptid != (ULONG *)NULL )
*ptid = prtn->prtn_id;
/*
** Return the number of buffers in the partition into
** the caller's storage location.
*/
if ( nbuf != (ULONG *)NULL )
*nbuf = prtn->free_blk_count;
}
else
{
/*
** Oops! Problem somewhere above. Release control block
** and data memory and return.
*/
ts_free( (void *)prtn->data_extent );
ts_free( (void *)prtn );
}
}
else
{
/*
** No memory for partition data... free partition control block
*/
ts_free( (void *)prtn );
error = ERR_OBJTFULL;
}
}
else
{
error = ERR_OBJTFULL;
}
return( error );
}
/*****************************************************************************
** delete_prtn - takes care of destroying the specified partition and freeing
** any resources allocated for that partition
*****************************************************************************/
static void
delete_prtn( p2pt_prtn_t *prtn )
{
/*
** First remove the partition from the partition list
*/
unlink_pcb( prtn->prtn_id );
/*
** Next delete the extent control block allocated for partition data.
*/
ts_free( (void *)prtn->data_extent );
/*
** Finally delete the partition control block itself;
*/
ts_free( (void *)prtn );
}
/*****************************************************************************
** pt_delete - removes the specified partition from the partition list and
** frees the memory allocated for the partition control block
** and extents.
*****************************************************************************/
ULONG
pt_delete( ULONG ptid )
{
p2pt_prtn_t *prtn;
ULONG error;
error = ERR_NO_ERROR;
if ( (prtn = pcb_for( ptid )) != (p2pt_prtn_t *)NULL )
{
/*
** Lock mutex for partition delete
*/
pthread_cleanup_push( (void(*)(void *))pthread_mutex_unlock,
(void *)&(prtn->prtn_lock));
pthread_mutex_lock( &(prtn->prtn_lock) );
if ( prtn->flags & PT_DEL )
{
/*
** Delete the partition even if buffers still allocated from it.
*/
/*
** Note: here we should not use pthread_mutex_unlock(&(prtn->prtn_lock))
** to unlock the mutex, cause delete_prtn has do it.
*/
sched_lock();
delete_prtn( prtn );
sched_unlock();
}
else
{
/*
** Ensure that none of the partition's buffers are allocated.
*/
sched_lock();
if ( prtn->used_blk_count > 0L )
{
error = ERR_BUFINUSE;
/*
** Unlock the mutex for the condition variable
*/
pthread_mutex_unlock( &(prtn->prtn_lock) );
}
else
{
/*
** No buffers are allocated from the partition. Delete it.
*/
error = ERR_NO_ERROR;
delete_prtn( prtn );
}
sched_unlock();
}
pthread_cleanup_pop( 0 );
}
else
{
error = ERR_OBJDEL;
}
return( error );
}
/*****************************************************************************
** pt_getbuf - obtains a free data buffer from the specified memory partition
*****************************************************************************/
ULONG
pt_getbuf( ULONG ptid, void **bufaddr )
{
p2pt_prtn_t *prtn;
char *blk_ptr;
ULONG error;
error = ERR_NO_ERROR;
if ( (prtn = pcb_for( ptid )) != (p2pt_prtn_t *)NULL )
{
/*
** Lock mutex for partition block allocation
*/
pthread_cleanup_push( (void(*)(void *))pthread_mutex_unlock,
(void *)&(prtn->prtn_lock));
pthread_mutex_lock( &(prtn->prtn_lock) );
/*
** Each free data block contains a pointer to the next free data
** block in the partition. This pointer is a pointer to a char
** as well as a pointer to a pointer to a char, since it is the
** address of both the next block and the next link pointer.
** The caller wants the address of a data block, so cast the
** first_free pointer to point to the first free data block
** and give that block to the caller. NOTE that if the free list
** is empty, blk_ptr will be returned as a NULL pointer.
*/
blk_ptr = (char *)prtn->first_free;
if ( blk_ptr != (char *)NULL )
{
/*
** Take the contents of the first free data block and interpret
** its first bytes as the address of the link pointer in the
** following data block. This address becomes the new value for
** the first_free pointer for the partition. This means data
** blocks are always allocated from the front of the free list.
*/
prtn->first_free = *((char ***)blk_ptr);
/*
** Adjust the block counters to reflect the fact that another
** block was just allocated.
*/
prtn->free_blk_count--;
prtn->used_blk_count++;
#ifdef DIAG_PRINTFS
printf( "\r\npt_getbuf allocated block @ %p from partition %ld nxt_blk @ %p",
blk_ptr, ptid, *((char **)blk_ptr) );
#endif
}
else
{
error = ERR_NOBUF;
#ifdef DIAG_PRINTFS
printf( "\r\npt_getbuf - no blocks free in partition %ld", ptid );
#endif
}
/*
** Unlock the mutex for the condition variable and clean up.
*/
pthread_mutex_unlock( &(prtn->prtn_lock) );
pthread_cleanup_pop( 0 );
}
else
{
blk_ptr = (char *)NULL;
error = ERR_OBJDEL; /* Invalid prtn specified */
#ifdef DIAG_PRINTFS
printf( "\r\npt_getbuf - partition %ld not found", ptid );
#endif
}
/*
** Return the allocated block address (or NULL) to the caller's
** storage location.
*/
if ( bufaddr != (void **)NULL )
*bufaddr = (void *)blk_ptr;
return( error );
}
/*****************************************************************************
** pt_retbuf - releases a data buffer back to the specified memory partition
*****************************************************************************/
ULONG
pt_retbuf( ULONG ptid, void *bufaddr )
{
p2pt_prtn_t *prtn;
prtn_extent_t *extent;
unsigned long extent_size;
char *blk_ptr;
ULONG error;
error = ERR_NO_ERROR;
if ( (prtn = pcb_for( ptid )) != (p2pt_prtn_t *)NULL )
{
/*
** Ensure that the block being returned falls within this
** partition's data memory range.
*/
blk_ptr = (char *)bufaddr;
extent = prtn->data_extent;
extent_size = extent->bcount * prtn->blk_size;
#ifdef DIAG_PRINTFS
printf( "\r\npt_retbuf bufaddr @ %p extent base @ %p size %lx",
blk_ptr, extent->baddr, extent_size );
#endif
if ( (blk_ptr == extent->baddr) ||
((blk_ptr > extent->baddr) &&
(blk_ptr < (extent->baddr + extent_size))) )
{
/*
** Lock mutex for partition block release
*/
pthread_cleanup_push( (void(*)(void *))pthread_mutex_unlock,
(void *)&(prtn->prtn_lock));
pthread_mutex_lock( &(prtn->prtn_lock) );
/*
** Search the partition's free list to see if the caller's
** buffer has already been freed.
*/
for ( blk_ptr = (char *)prtn->first_free;
blk_ptr != (char *)NULL;
blk_ptr = *(char **)blk_ptr )
{
#ifdef DIAG_PRINTFS
printf( "\r\npt_retbuf cur_blk @ %p nxt_blk @ %p",
blk_ptr, *(char **)blk_ptr );
#endif
if ( blk_ptr == (char *)bufaddr )
{
error = ERR_BUFFREE;
break;
}
}
if ( error == ERR_NO_ERROR )
{
/*
** The caller's buffer address falls within the partition
** and has not already been freed...
** Insert a list-terminating NULL pointer into the block
** being freed up. Then link the block into the free list
** after the previous last free block. This means free blocks
** are always returned to the rear of the free list, ensuring
** an even distribution of use for the blocks in the partition.
*/
blk_ptr = (char *)bufaddr;
*(char **)blk_ptr = (char *)NULL;
*(prtn->last_free) = blk_ptr;
prtn->last_free = (char **)blk_ptr;
if ( prtn->first_free == (char **)NULL )
prtn->first_free = (char **)blk_ptr;
#ifdef DIAG_PRINTFS
printf( "\r\npt_retbuf returned block @ %p to partition %ld",
blk_ptr, ptid );
#endif
/*
** Adjust the block counters to reflect the fact that another
** block was just released.
*/
prtn->free_blk_count++;
prtn->used_blk_count--;
}
#ifdef DIAG_PRINTFS
else
{
printf( "\r\npt_retbuf - block @ %p already freed", blk_ptr );
}
#endif
/*
** Unlock the mutex for the condition variable and clean up.
*/
pthread_mutex_unlock( &(prtn->prtn_lock) );
pthread_cleanup_pop( 0 );
}
else
{
error = ERR_BUFADDR;
#ifdef DIAG_PRINTFS
printf( "\r\npt_retbuf - block @ %p not in partition %ld",
blk_ptr, ptid );
#endif
}
}
else
{
error = ERR_OBJDEL; /* Invalid prtn specified */
}
return( error );
}
/*****************************************************************************
** pt_ident - identifies the named p2pthread partition
*****************************************************************************/
ULONG
pt_ident( char name[4], ULONG node, ULONG *ptid )
{
p2pt_prtn_t *current_pcb;
ULONG error;
error = ERR_NO_ERROR;
/*
** Validate the node specifier... only zero is allowed here.
*/
if ( node != 0L )
error = ERR_NODENO;
else
{
/*
** If queue name string is a NULL pointer, return with error.
** We'll ASSUME the ptid pointer isn't NULL!
*/
if ( name == (char *)NULL )
{
*ptid = (ULONG)NULL;
error = ERR_OBJNF;
}
else
{
/*
** Scan the task list for a name matching the caller's name.
*/
for ( current_pcb = prtn_list;
current_pcb != (p2pt_prtn_t *)NULL;
current_pcb = current_pcb->nxt_prtn )
{
if ( (strncmp( name, current_pcb->ptname, 4 )) == 0 )
{
/*
** A matching name was found... return its QID
*/
*ptid = current_pcb->prtn_id;
break;
}
}
if ( current_pcb == (p2pt_prtn_t *)NULL )
{
/*
** No matching name found... return caller's QID with error.
*/
*ptid = (ULONG)NULL;
error = ERR_OBJNF;
}
}
}
return( error );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -