Split Heap and Time of Day Handlers.

This commit is contained in:
Joel Sherrill
1999-11-02 21:05:17 +00:00
parent dfbfa2b029
commit 93b4e6ef7e
27 changed files with 1738 additions and 3072 deletions

View File

@@ -22,6 +22,9 @@ INSTALL_CHANGE = @INSTALL_CHANGE@
MP_C_PIECES_yes_V = mpci objectmp threadmp
MP_C_PIECES = $(MP_C_PIECES_$(HAS_MP)_V)
HEAP_C_PIECES = heap heapallocate heapextend heapfree \
heapsizeofuserarea heapwalk
OBJECT_C_PIECES = object objectallocate objectallocatebyindex \
objectclearname objectcomparenameraw objectcomparenamestring \
objectcopynameraw objectcopynamestring objectextendinformation \
@@ -42,9 +45,13 @@ THREADQ_C_PIECES= threadq threadqdequeue threadqdequeuefifo \
threadqextractpriority threadqextractwithproxy threadqfirst \
threadqfirstfifo threadqfirstpriority threadqflush threadqtimeout
TOD_C_PIECES= coretod coretodset coretodtickle coretodtoseconds \
coretodvalidate
# C and C++ source names, if any, go here -- minus the .c or .cc
C_PIECES = apiext chain coremsg coremutex coresem coretod heap interr isr \
$(OBJECT_C_PIECES) $(THREAD_C_PIECES) $(THREADQ_C_PIECES) userext \
C_PIECES = apiext chain coremsg coremutex coresem $(HEAP_C_PIECES) interr isr \
$(OBJECT_C_PIECES) $(THREAD_C_PIECES) $(THREADQ_C_PIECES) \
$(TOD_C_PIECES) userext \
watchdog wkspace $(MP_C_PIECES)
C_FILES = $(C_PIECES:%=%.c)
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)

View File

@@ -58,181 +58,3 @@ void _TOD_Handler_initialization(
_TOD_Is_set = FALSE;
_TOD_Activate( _TOD_Ticks_per_second );
}
/*PAGE
*
* _TOD_Set
*
* This rountine sets the current date and time with the specified
* new date and time structure.
*
* Input parameters:
* the_tod - pointer to the time and date structure
* seconds_since_epoch - seconds since system epoch
*
* Output parameters: NONE
*/
void _TOD_Set(
TOD_Control *the_tod,
Watchdog_Interval seconds_since_epoch
)
{
Watchdog_Interval ticks_until_next_second;
_Thread_Disable_dispatch();
_TOD_Deactivate();
if ( seconds_since_epoch < _TOD_Seconds_since_epoch )
_Watchdog_Adjust_seconds( WATCHDOG_BACKWARD,
_TOD_Seconds_since_epoch - seconds_since_epoch );
else
_Watchdog_Adjust_seconds( WATCHDOG_FORWARD,
seconds_since_epoch - _TOD_Seconds_since_epoch );
ticks_until_next_second = _TOD_Ticks_per_second;
if ( ticks_until_next_second > _TOD_Current.ticks )
ticks_until_next_second -= _TOD_Current.ticks;
_TOD_Current = *the_tod;
_TOD_Seconds_since_epoch = seconds_since_epoch;
_TOD_Is_set = TRUE;
_TOD_Activate( ticks_until_next_second );
_Thread_Enable_dispatch();
}
/*PAGE
*
* _TOD_Validate
*
* This kernel routine checks the validity of a date and time structure.
*
* Input parameters:
* the_tod - pointer to a time and date structure
*
* Output parameters:
* TRUE - if the date, time, and tick are valid
* FALSE - if the the_tod is invalid
*
* NOTE: This routine only works for leap-years through 2099.
*/
boolean _TOD_Validate(
TOD_Control *the_tod
)
{
unsigned32 days_in_month;
if ((the_tod->ticks >= _TOD_Ticks_per_second) ||
(the_tod->second >= TOD_SECONDS_PER_MINUTE) ||
(the_tod->minute >= TOD_MINUTES_PER_HOUR) ||
(the_tod->hour >= TOD_HOURS_PER_DAY) ||
(the_tod->month == 0) ||
(the_tod->month > TOD_MONTHS_PER_YEAR) ||
(the_tod->year < TOD_BASE_YEAR) ||
(the_tod->day == 0) )
return FALSE;
if ( (the_tod->year % 4) == 0 )
days_in_month = _TOD_Days_per_month[ 1 ][ the_tod->month ];
else
days_in_month = _TOD_Days_per_month[ 0 ][ the_tod->month ];
if ( the_tod->day > days_in_month )
return FALSE;
return TRUE;
}
/*PAGE
*
* _TOD_To_seconds
*
* This routine returns the seconds from the epoch until the
* current date and time.
*
* Input parameters:
* the_tod - pointer to the time and date structure
*
* Output parameters:
* returns - seconds since epoch until the_tod
*/
unsigned32 _TOD_To_seconds(
TOD_Control *the_tod
)
{
unsigned32 time;
unsigned32 year_mod_4;
time = the_tod->day - 1;
year_mod_4 = the_tod->year & 3;
if ( year_mod_4 == 0 )
time += _TOD_Days_to_date[ 1 ][ the_tod->month ];
else
time += _TOD_Days_to_date[ 0 ][ the_tod->month ];
time += ( (the_tod->year - TOD_BASE_YEAR) / 4 ) *
( (TOD_DAYS_PER_YEAR * 4) + 1);
time += _TOD_Days_since_last_leap_year[ year_mod_4 ];
time *= TOD_SECONDS_PER_DAY;
time += ((the_tod->hour * TOD_MINUTES_PER_HOUR) + the_tod->minute)
* TOD_SECONDS_PER_MINUTE;
time += the_tod->second;
return( time );
}
/*PAGE
*
* _TOD_Tickle
*
* This routine updates the calendar time and tickles the
* per second watchdog timer chain.
*
* Input parameters:
* ignored - this parameter is ignored
*
* Output parameters: NONE
*
* NOTE: This routine only works for leap-years through 2099.
*/
void _TOD_Tickle(
Objects_Id id,
void *ignored
)
{
unsigned32 leap;
_TOD_Current.ticks = 0;
++_TOD_Seconds_since_epoch;
if ( ++_TOD_Current.second >= TOD_SECONDS_PER_MINUTE ) {
_TOD_Current.second = 0;
if ( ++_TOD_Current.minute >= TOD_MINUTES_PER_HOUR ) {
_TOD_Current.minute = 0;
if ( ++_TOD_Current.hour >= TOD_HOURS_PER_DAY ) {
_TOD_Current.hour = 0;
if ( _TOD_Current.year & 0x3 ) leap = 0;
else leap = 1;
if ( ++_TOD_Current.day >
_TOD_Days_per_month[ leap ][ _TOD_Current.month ]) {
_TOD_Current.day = 1;
if ( ++_TOD_Current.month > TOD_MONTHS_PER_YEAR ) {
_TOD_Current.month = 1;
_TOD_Current.year++;
}
}
}
}
}
_Watchdog_Tickle_seconds();
_Watchdog_Insert_ticks( &_TOD_Seconds_watchdog, _TOD_Ticks_per_second );
}

View File

@@ -0,0 +1,64 @@
/*
* Time of Day (TOD) Handler
*
*
* COPYRIGHT (c) 1989-1998.
* On-Line Applications Research Corporation (OAR).
* Copyright assigned to U.S. Government, 1994.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <rtems/system.h>
#include <rtems/score/object.h>
#include <rtems/score/thread.h>
#include <rtems/score/tod.h>
#include <rtems/score/watchdog.h>
/*PAGE
*
* _TOD_Set
*
* This rountine sets the current date and time with the specified
* new date and time structure.
*
* Input parameters:
* the_tod - pointer to the time and date structure
* seconds_since_epoch - seconds since system epoch
*
* Output parameters: NONE
*/
void _TOD_Set(
TOD_Control *the_tod,
Watchdog_Interval seconds_since_epoch
)
{
Watchdog_Interval ticks_until_next_second;
_Thread_Disable_dispatch();
_TOD_Deactivate();
if ( seconds_since_epoch < _TOD_Seconds_since_epoch )
_Watchdog_Adjust_seconds( WATCHDOG_BACKWARD,
_TOD_Seconds_since_epoch - seconds_since_epoch );
else
_Watchdog_Adjust_seconds( WATCHDOG_FORWARD,
seconds_since_epoch - _TOD_Seconds_since_epoch );
ticks_until_next_second = _TOD_Ticks_per_second;
if ( ticks_until_next_second > _TOD_Current.ticks )
ticks_until_next_second -= _TOD_Current.ticks;
_TOD_Current = *the_tod;
_TOD_Seconds_since_epoch = seconds_since_epoch;
_TOD_Is_set = TRUE;
_TOD_Activate( ticks_until_next_second );
_Thread_Enable_dispatch();
}

View File

@@ -0,0 +1,68 @@
/*
* Time of Day (TOD) Handler
*
*
* COPYRIGHT (c) 1989-1998.
* On-Line Applications Research Corporation (OAR).
* Copyright assigned to U.S. Government, 1994.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <rtems/system.h>
#include <rtems/score/object.h>
#include <rtems/score/thread.h>
#include <rtems/score/tod.h>
#include <rtems/score/watchdog.h>
/*PAGE
*
* _TOD_Tickle
*
* This routine updates the calendar time and tickles the
* per second watchdog timer chain.
*
* Input parameters:
* ignored - this parameter is ignored
*
* Output parameters: NONE
*
* NOTE: This routine only works for leap-years through 2099.
*/
void _TOD_Tickle(
Objects_Id id,
void *ignored
)
{
unsigned32 leap;
_TOD_Current.ticks = 0;
++_TOD_Seconds_since_epoch;
if ( ++_TOD_Current.second >= TOD_SECONDS_PER_MINUTE ) {
_TOD_Current.second = 0;
if ( ++_TOD_Current.minute >= TOD_MINUTES_PER_HOUR ) {
_TOD_Current.minute = 0;
if ( ++_TOD_Current.hour >= TOD_HOURS_PER_DAY ) {
_TOD_Current.hour = 0;
if ( _TOD_Current.year & 0x3 ) leap = 0;
else leap = 1;
if ( ++_TOD_Current.day >
_TOD_Days_per_month[ leap ][ _TOD_Current.month ]) {
_TOD_Current.day = 1;
if ( ++_TOD_Current.month > TOD_MONTHS_PER_YEAR ) {
_TOD_Current.month = 1;
_TOD_Current.year++;
}
}
}
}
}
_Watchdog_Tickle_seconds();
_Watchdog_Insert_ticks( &_TOD_Seconds_watchdog, _TOD_Ticks_per_second );
}

View File

@@ -0,0 +1,65 @@
/*
* Time of Day (TOD) Handler
*
*
* COPYRIGHT (c) 1989-1998.
* On-Line Applications Research Corporation (OAR).
* Copyright assigned to U.S. Government, 1994.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <rtems/system.h>
#include <rtems/score/object.h>
#include <rtems/score/thread.h>
#include <rtems/score/tod.h>
#include <rtems/score/watchdog.h>
/*PAGE
*
* _TOD_To_seconds
*
* This routine returns the seconds from the epoch until the
* current date and time.
*
* Input parameters:
* the_tod - pointer to the time and date structure
*
* Output parameters:
* returns - seconds since epoch until the_tod
*/
unsigned32 _TOD_To_seconds(
TOD_Control *the_tod
)
{
unsigned32 time;
unsigned32 year_mod_4;
time = the_tod->day - 1;
year_mod_4 = the_tod->year & 3;
if ( year_mod_4 == 0 )
time += _TOD_Days_to_date[ 1 ][ the_tod->month ];
else
time += _TOD_Days_to_date[ 0 ][ the_tod->month ];
time += ( (the_tod->year - TOD_BASE_YEAR) / 4 ) *
( (TOD_DAYS_PER_YEAR * 4) + 1);
time += _TOD_Days_since_last_leap_year[ year_mod_4 ];
time *= TOD_SECONDS_PER_DAY;
time += ((the_tod->hour * TOD_MINUTES_PER_HOUR) + the_tod->minute)
* TOD_SECONDS_PER_MINUTE;
time += the_tod->second;
return( time );
}

View File

@@ -0,0 +1,64 @@
/*
* Time of Day (TOD) Handler
*
*
* COPYRIGHT (c) 1989-1998.
* On-Line Applications Research Corporation (OAR).
* Copyright assigned to U.S. Government, 1994.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <rtems/system.h>
#include <rtems/score/object.h>
#include <rtems/score/thread.h>
#include <rtems/score/tod.h>
#include <rtems/score/watchdog.h>
/*PAGE
*
* _TOD_Validate
*
* This kernel routine checks the validity of a date and time structure.
*
* Input parameters:
* the_tod - pointer to a time and date structure
*
* Output parameters:
* TRUE - if the date, time, and tick are valid
* FALSE - if the the_tod is invalid
*
* NOTE: This routine only works for leap-years through 2099.
*/
boolean _TOD_Validate(
TOD_Control *the_tod
)
{
unsigned32 days_in_month;
if ((the_tod->ticks >= _TOD_Ticks_per_second) ||
(the_tod->second >= TOD_SECONDS_PER_MINUTE) ||
(the_tod->minute >= TOD_MINUTES_PER_HOUR) ||
(the_tod->hour >= TOD_HOURS_PER_DAY) ||
(the_tod->month == 0) ||
(the_tod->month > TOD_MONTHS_PER_YEAR) ||
(the_tod->year < TOD_BASE_YEAR) ||
(the_tod->day == 0) )
return FALSE;
if ( (the_tod->year % 4) == 0 )
days_in_month = _TOD_Days_per_month[ 1 ][ the_tod->month ];
else
days_in_month = _TOD_Days_per_month[ 0 ][ the_tod->month ];
if ( the_tod->day > days_in_month )
return FALSE;
return TRUE;
}

View File

@@ -92,447 +92,3 @@ unsigned32 _Heap_Initialize(
return ( the_size - HEAP_BLOCK_USED_OVERHEAD );
}
/*PAGE
*
* _Heap_Extend
*
* This routine grows the_heap memory area using the size bytes which
* begin at starting_address.
*
* Input parameters:
* the_heap - pointer to heap header.
* starting_address - pointer to the memory area.
* size - size in bytes of the memory block to allocate.
*
* Output parameters:
* *amount_extended - amount of memory added to the_heap
*/
Heap_Extend_status _Heap_Extend(
Heap_Control *the_heap,
void *starting_address,
unsigned32 size,
unsigned32 *amount_extended
)
{
Heap_Block *the_block;
unsigned32 *p;
/*
* The overhead was taken from the original heap memory.
*/
Heap_Block *old_final;
Heap_Block *new_final;
/*
* There are five possibilities for the location of starting
* address:
*
* 1. non-contiguous lower address (NOT SUPPORTED)
* 2. contiguous lower address (NOT SUPPORTED)
* 3. in the heap (ERROR)
* 4. contiguous higher address (SUPPORTED)
* 5. non-contiguous higher address (NOT SUPPORTED)
*
* As noted, this code only supports (4).
*/
if ( starting_address >= (void *) the_heap->start && /* case 3 */
starting_address <= (void *) the_heap->final
)
return HEAP_EXTEND_ERROR;
if ( starting_address < (void *) the_heap->start ) { /* cases 1 and 2 */
return HEAP_EXTEND_NOT_IMPLEMENTED; /* cases 1 and 2 */
} else { /* cases 4 and 5 */
the_block = (Heap_Block *)
_Addresses_Subtract_offset( starting_address, HEAP_OVERHEAD );
if ( the_block != the_heap->final )
return HEAP_EXTEND_NOT_IMPLEMENTED; /* case 5 */
}
/*
* Currently only case 4 should make it to this point.
* The basic trick is to make the extend area look like a used
* block and free it.
*/
*amount_extended = size;
old_final = the_heap->final;
new_final = _Addresses_Add_offset( old_final, size );
/* SAME AS: _Addresses_Add_offset( starting_address, size-HEAP_OVERHEAD ); */
the_heap->final = new_final;
old_final->front_flag =
new_final->back_flag = _Heap_Build_flag( size, HEAP_BLOCK_USED );
new_final->front_flag = HEAP_DUMMY_FLAG;
/*
* Must pass in address of "user" area
* So add in the offset field.
*/
p = (unsigned32 *) &old_final->next;
*p = sizeof(unsigned32);
p++;
_Heap_Free( the_heap, p );
return HEAP_EXTEND_SUCCESSFUL;
}
/*PAGE
*
* _Heap_Allocate
*
* This kernel routine allocates the requested size of memory
* from the specified heap.
*
* Input parameters:
* the_heap - pointer to heap header.
* size - size in bytes of the memory block to allocate.
*
* Output parameters:
* returns - starting address of memory block allocated
*/
void *_Heap_Allocate(
Heap_Control *the_heap,
unsigned32 size
)
{
unsigned32 excess;
unsigned32 the_size;
Heap_Block *the_block;
Heap_Block *next_block;
Heap_Block *temporary_block;
void *ptr;
unsigned32 offset;
excess = size % the_heap->page_size;
the_size = size + the_heap->page_size + HEAP_BLOCK_USED_OVERHEAD;
if ( excess )
the_size += the_heap->page_size - excess;
if ( the_size < sizeof( Heap_Block ) )
the_size = sizeof( Heap_Block );
for ( the_block = the_heap->first;
;
the_block = the_block->next ) {
if ( the_block == _Heap_Tail( the_heap ) )
return( NULL );
if ( the_block->front_flag >= the_size )
break;
}
if ( (the_block->front_flag - the_size) >
(the_heap->page_size + HEAP_BLOCK_USED_OVERHEAD) ) {
the_block->front_flag -= the_size;
next_block = _Heap_Next_block( the_block );
next_block->back_flag = the_block->front_flag;
temporary_block = _Heap_Block_at( next_block, the_size );
temporary_block->back_flag =
next_block->front_flag = _Heap_Build_flag( the_size,
HEAP_BLOCK_USED );
ptr = _Heap_Start_of_user_area( next_block );
} else {
next_block = _Heap_Next_block( the_block );
next_block->back_flag = _Heap_Build_flag( the_block->front_flag,
HEAP_BLOCK_USED );
the_block->front_flag = next_block->back_flag;
the_block->next->previous = the_block->previous;
the_block->previous->next = the_block->next;
ptr = _Heap_Start_of_user_area( the_block );
}
/*
* round ptr up to a multiple of page size
* Have to save the bump amount in the buffer so that free can figure it out
*/
offset = the_heap->page_size - (((unsigned32) ptr) & (the_heap->page_size - 1));
ptr = _Addresses_Add_offset( ptr, offset );
*(((unsigned32 *) ptr) - 1) = offset;
#ifdef RTEMS_DEBUG
{
unsigned32 ptr_u32;
ptr_u32 = (unsigned32) ptr;
if (ptr_u32 & (the_heap->page_size - 1))
abort();
}
#endif
return ptr;
}
/*PAGE
*
* _Heap_Size_of_user_area
*
* This kernel routine returns the size of the memory area
* given heap block.
*
* Input parameters:
* the_heap - pointer to heap header
* starting_address - starting address of the memory block to free.
* size - pointer to size of area
*
* Output parameters:
* size - size of area filled in
* TRUE - if starting_address is valid heap address
* FALSE - if starting_address is invalid heap address
*/
boolean _Heap_Size_of_user_area(
Heap_Control *the_heap,
void *starting_address,
unsigned32 *size
)
{
Heap_Block *the_block;
Heap_Block *next_block;
unsigned32 the_size;
the_block = _Heap_User_block_at( starting_address );
if ( !_Heap_Is_block_in( the_heap, the_block ) ||
_Heap_Is_block_free( the_block ) )
return( FALSE );
the_size = _Heap_Block_size( the_block );
next_block = _Heap_Block_at( the_block, the_size );
if ( !_Heap_Is_block_in( the_heap, next_block ) ||
(the_block->front_flag != next_block->back_flag) )
return( FALSE );
*size = the_size;
return( TRUE );
}
/*PAGE
*
* _Heap_Free
*
* This kernel routine returns the memory designated by the
* given heap and given starting address to the memory pool.
*
* Input parameters:
* the_heap - pointer to heap header
* starting_address - starting address of the memory block to free.
*
* Output parameters:
* TRUE - if starting_address is valid heap address
* FALSE - if starting_address is invalid heap address
*/
boolean _Heap_Free(
Heap_Control *the_heap,
void *starting_address
)
{
Heap_Block *the_block;
Heap_Block *next_block;
Heap_Block *new_next_block;
Heap_Block *previous_block;
Heap_Block *temporary_block;
unsigned32 the_size;
the_block = _Heap_User_block_at( starting_address );
if ( !_Heap_Is_block_in( the_heap, the_block ) ||
_Heap_Is_block_free( the_block ) ) {
return( FALSE );
}
the_size = _Heap_Block_size( the_block );
next_block = _Heap_Block_at( the_block, the_size );
if ( !_Heap_Is_block_in( the_heap, next_block ) ||
(the_block->front_flag != next_block->back_flag) ) {
return( FALSE );
}
if ( _Heap_Is_previous_block_free( the_block ) ) {
previous_block = _Heap_Previous_block( the_block );
if ( !_Heap_Is_block_in( the_heap, previous_block ) ) {
return( FALSE );
}
if ( _Heap_Is_block_free( next_block ) ) { /* coalesce both */
previous_block->front_flag += next_block->front_flag + the_size;
temporary_block = _Heap_Next_block( previous_block );
temporary_block->back_flag = previous_block->front_flag;
next_block->next->previous = next_block->previous;
next_block->previous->next = next_block->next;
}
else { /* coalesce prev */
previous_block->front_flag =
next_block->back_flag = previous_block->front_flag + the_size;
}
}
else if ( _Heap_Is_block_free( next_block ) ) { /* coalesce next */
the_block->front_flag = the_size + next_block->front_flag;
new_next_block = _Heap_Next_block( the_block );
new_next_block->back_flag = the_block->front_flag;
the_block->next = next_block->next;
the_block->previous = next_block->previous;
next_block->previous->next = the_block;
next_block->next->previous = the_block;
if (the_heap->first == next_block)
the_heap->first = the_block;
}
else { /* no coalesce */
next_block->back_flag =
the_block->front_flag = the_size;
the_block->previous = _Heap_Head( the_heap );
the_block->next = the_heap->first;
the_heap->first = the_block;
the_block->next->previous = the_block;
}
return( TRUE );
}
/*PAGE
*
* _Heap_Walk
*
* This kernel routine walks the heap and verifies its correctness.
*
* Input parameters:
* the_heap - pointer to heap header
* source - a numeric indicator of the invoker of this routine
* do_dump - when TRUE print the information
*
* Output parameters: NONE
*/
#ifndef RTEMS_DEBUG
void _Heap_Walk(
Heap_Control *the_heap,
int source,
boolean do_dump
)
{
}
#else
#include <stdio.h>
#include <unistd.h>
void _Heap_Walk(
Heap_Control *the_heap,
int source,
boolean do_dump
)
{
Heap_Block *the_block = 0; /* avoid warnings */
Heap_Block *next_block = 0; /* avoid warnings */
int notdone = 1;
int error = 0;
int passes = 0;
/*
* We don't want to allow walking the heap until we have
* transferred control to the user task so we watch the
* system state.
*/
if ( !_System_state_Is_up( _System_state_Get() ) )
return;
the_block = the_heap->start;
if (do_dump == TRUE) {
printf("\nPASS: %d start @ 0x%p final 0x%p, first 0x%p last 0x%p\n",
source, the_heap->start, the_heap->final,
the_heap->first, the_heap->last
);
}
/*
* Handle the 1st block
*/
if (the_block->back_flag != HEAP_DUMMY_FLAG) {
printf("PASS: %d Back flag of 1st block isn't HEAP_DUMMY_FLAG\n", source);
error = 1;
}
while (notdone) {
passes++;
if (error && (passes > 10))
abort();
if (do_dump == TRUE) {
printf("PASS: %d Block @ 0x%p Back %d, Front %d",
source, the_block,
the_block->back_flag, the_block->front_flag);
if ( _Heap_Is_block_free(the_block) ) {
printf( " Prev 0x%p, Next 0x%p\n",
the_block->previous, the_block->next);
} else {
printf("\n");
}
}
/*
* Handle the last block
*/
if ( the_block->front_flag != HEAP_DUMMY_FLAG ) {
next_block = _Heap_Next_block(the_block);
if ( the_block->front_flag != next_block->back_flag ) {
error = 1;
printf("PASS: %d Front and back flags don't match\n", source);
printf(" Current Block (%p): Back - %d, Front - %d",
the_block, the_block->back_flag, the_block->front_flag);
if (do_dump == TRUE) {
if (_Heap_Is_block_free(the_block)) {
printf(" Prev 0x%p, Next 0x%p\n",
the_block->previous, the_block->next);
} else {
printf("\n");
}
} else {
printf("\n");
}
printf(" Next Block (%p): Back - %d, Front - %d",
next_block, next_block->back_flag, next_block->front_flag);
if (do_dump == TRUE) {
if (_Heap_Is_block_free(next_block)) {
printf(" Prev 0x%p, Next 0x%p\n",
the_block->previous, the_block->next);
} else {
printf("\n");
}
} else {
printf("\n");
}
}
}
if (the_block->front_flag == HEAP_DUMMY_FLAG)
notdone = 0;
else
the_block = next_block;
}
if (error)
abort();
}
#endif

View File

@@ -0,0 +1,107 @@
/*
* Heap Handler
*
* COPYRIGHT (c) 1989-1998.
* On-Line Applications Research Corporation (OAR).
* Copyright assigned to U.S. Government, 1994.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <rtems/system.h>
#include <rtems/score/sysstate.h>
#include <rtems/score/heap.h>
/*PAGE
*
* _Heap_Allocate
*
* This kernel routine allocates the requested size of memory
* from the specified heap.
*
* Input parameters:
* the_heap - pointer to heap header.
* size - size in bytes of the memory block to allocate.
*
* Output parameters:
* returns - starting address of memory block allocated
*/
void *_Heap_Allocate(
Heap_Control *the_heap,
unsigned32 size
)
{
unsigned32 excess;
unsigned32 the_size;
Heap_Block *the_block;
Heap_Block *next_block;
Heap_Block *temporary_block;
void *ptr;
unsigned32 offset;
excess = size % the_heap->page_size;
the_size = size + the_heap->page_size + HEAP_BLOCK_USED_OVERHEAD;
if ( excess )
the_size += the_heap->page_size - excess;
if ( the_size < sizeof( Heap_Block ) )
the_size = sizeof( Heap_Block );
for ( the_block = the_heap->first;
;
the_block = the_block->next ) {
if ( the_block == _Heap_Tail( the_heap ) )
return( NULL );
if ( the_block->front_flag >= the_size )
break;
}
if ( (the_block->front_flag - the_size) >
(the_heap->page_size + HEAP_BLOCK_USED_OVERHEAD) ) {
the_block->front_flag -= the_size;
next_block = _Heap_Next_block( the_block );
next_block->back_flag = the_block->front_flag;
temporary_block = _Heap_Block_at( next_block, the_size );
temporary_block->back_flag =
next_block->front_flag = _Heap_Build_flag( the_size,
HEAP_BLOCK_USED );
ptr = _Heap_Start_of_user_area( next_block );
} else {
next_block = _Heap_Next_block( the_block );
next_block->back_flag = _Heap_Build_flag( the_block->front_flag,
HEAP_BLOCK_USED );
the_block->front_flag = next_block->back_flag;
the_block->next->previous = the_block->previous;
the_block->previous->next = the_block->next;
ptr = _Heap_Start_of_user_area( the_block );
}
/*
* round ptr up to a multiple of page size
* Have to save the bump amount in the buffer so that free can figure it out
*/
offset = the_heap->page_size - (((unsigned32) ptr) & (the_heap->page_size - 1));
ptr = _Addresses_Add_offset( ptr, offset );
*(((unsigned32 *) ptr) - 1) = offset;
#ifdef RTEMS_DEBUG
{
unsigned32 ptr_u32;
ptr_u32 = (unsigned32) ptr;
if (ptr_u32 & (the_heap->page_size - 1))
abort();
}
#endif
return ptr;
}

View File

@@ -0,0 +1,113 @@
/*
* Heap Handler
*
* COPYRIGHT (c) 1989-1998.
* On-Line Applications Research Corporation (OAR).
* Copyright assigned to U.S. Government, 1994.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <rtems/system.h>
#include <rtems/score/sysstate.h>
#include <rtems/score/heap.h>
/*PAGE
*
* _Heap_Extend
*
* This routine grows the_heap memory area using the size bytes which
* begin at starting_address.
*
* Input parameters:
* the_heap - pointer to heap header.
* starting_address - pointer to the memory area.
* size - size in bytes of the memory block to allocate.
*
* Output parameters:
* *amount_extended - amount of memory added to the_heap
*/
Heap_Extend_status _Heap_Extend(
Heap_Control *the_heap,
void *starting_address,
unsigned32 size,
unsigned32 *amount_extended
)
{
Heap_Block *the_block;
unsigned32 *p;
/*
* The overhead was taken from the original heap memory.
*/
Heap_Block *old_final;
Heap_Block *new_final;
/*
* There are five possibilities for the location of starting
* address:
*
* 1. non-contiguous lower address (NOT SUPPORTED)
* 2. contiguous lower address (NOT SUPPORTED)
* 3. in the heap (ERROR)
* 4. contiguous higher address (SUPPORTED)
* 5. non-contiguous higher address (NOT SUPPORTED)
*
* As noted, this code only supports (4).
*/
if ( starting_address >= (void *) the_heap->start && /* case 3 */
starting_address <= (void *) the_heap->final
)
return HEAP_EXTEND_ERROR;
if ( starting_address < (void *) the_heap->start ) { /* cases 1 and 2 */
return HEAP_EXTEND_NOT_IMPLEMENTED; /* cases 1 and 2 */
} else { /* cases 4 and 5 */
the_block = (Heap_Block *)
_Addresses_Subtract_offset( starting_address, HEAP_OVERHEAD );
if ( the_block != the_heap->final )
return HEAP_EXTEND_NOT_IMPLEMENTED; /* case 5 */
}
/*
* Currently only case 4 should make it to this point.
* The basic trick is to make the extend area look like a used
* block and free it.
*/
*amount_extended = size;
old_final = the_heap->final;
new_final = _Addresses_Add_offset( old_final, size );
/* SAME AS: _Addresses_Add_offset( starting_address, size-HEAP_OVERHEAD ); */
the_heap->final = new_final;
old_final->front_flag =
new_final->back_flag = _Heap_Build_flag( size, HEAP_BLOCK_USED );
new_final->front_flag = HEAP_DUMMY_FLAG;
/*
* Must pass in address of "user" area
* So add in the offset field.
*/
p = (unsigned32 *) &old_final->next;
*p = sizeof(unsigned32);
p++;
_Heap_Free( the_heap, p );
return HEAP_EXTEND_SUCCESSFUL;
}

View File

@@ -0,0 +1,105 @@
/*
* Heap Handler
*
* COPYRIGHT (c) 1989-1998.
* On-Line Applications Research Corporation (OAR).
* Copyright assigned to U.S. Government, 1994.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <rtems/system.h>
#include <rtems/score/sysstate.h>
#include <rtems/score/heap.h>
/*PAGE
*
* _Heap_Free
*
* This kernel routine returns the memory designated by the
* given heap and given starting address to the memory pool.
*
* Input parameters:
* the_heap - pointer to heap header
* starting_address - starting address of the memory block to free.
*
* Output parameters:
* TRUE - if starting_address is valid heap address
* FALSE - if starting_address is invalid heap address
*/
boolean _Heap_Free(
Heap_Control *the_heap,
void *starting_address
)
{
Heap_Block *the_block;
Heap_Block *next_block;
Heap_Block *new_next_block;
Heap_Block *previous_block;
Heap_Block *temporary_block;
unsigned32 the_size;
the_block = _Heap_User_block_at( starting_address );
if ( !_Heap_Is_block_in( the_heap, the_block ) ||
_Heap_Is_block_free( the_block ) ) {
return( FALSE );
}
the_size = _Heap_Block_size( the_block );
next_block = _Heap_Block_at( the_block, the_size );
if ( !_Heap_Is_block_in( the_heap, next_block ) ||
(the_block->front_flag != next_block->back_flag) ) {
return( FALSE );
}
if ( _Heap_Is_previous_block_free( the_block ) ) {
previous_block = _Heap_Previous_block( the_block );
if ( !_Heap_Is_block_in( the_heap, previous_block ) ) {
return( FALSE );
}
if ( _Heap_Is_block_free( next_block ) ) { /* coalesce both */
previous_block->front_flag += next_block->front_flag + the_size;
temporary_block = _Heap_Next_block( previous_block );
temporary_block->back_flag = previous_block->front_flag;
next_block->next->previous = next_block->previous;
next_block->previous->next = next_block->next;
}
else { /* coalesce prev */
previous_block->front_flag =
next_block->back_flag = previous_block->front_flag + the_size;
}
}
else if ( _Heap_Is_block_free( next_block ) ) { /* coalesce next */
the_block->front_flag = the_size + next_block->front_flag;
new_next_block = _Heap_Next_block( the_block );
new_next_block->back_flag = the_block->front_flag;
the_block->next = next_block->next;
the_block->previous = next_block->previous;
next_block->previous->next = the_block;
next_block->next->previous = the_block;
if (the_heap->first == next_block)
the_heap->first = the_block;
}
else { /* no coalesce */
next_block->back_flag =
the_block->front_flag = the_size;
the_block->previous = _Heap_Head( the_heap );
the_block->next = the_heap->first;
the_heap->first = the_block;
the_block->next->previous = the_block;
}
return( TRUE );
}

View File

@@ -0,0 +1,64 @@
/*
* Heap Handler
*
* COPYRIGHT (c) 1989-1998.
* On-Line Applications Research Corporation (OAR).
* Copyright assigned to U.S. Government, 1994.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <rtems/system.h>
#include <rtems/score/sysstate.h>
#include <rtems/score/heap.h>
/*PAGE
*
* _Heap_Size_of_user_area
*
* This kernel routine returns the size of the memory area
* given heap block.
*
* Input parameters:
* the_heap - pointer to heap header
* starting_address - starting address of the memory block to free.
* size - pointer to size of area
*
* Output parameters:
* size - size of area filled in
* TRUE - if starting_address is valid heap address
* FALSE - if starting_address is invalid heap address
*/
boolean _Heap_Size_of_user_area(
Heap_Control *the_heap,
void *starting_address,
unsigned32 *size
)
{
Heap_Block *the_block;
Heap_Block *next_block;
unsigned32 the_size;
the_block = _Heap_User_block_at( starting_address );
if ( !_Heap_Is_block_in( the_heap, the_block ) ||
_Heap_Is_block_free( the_block ) )
return( FALSE );
the_size = _Heap_Block_size( the_block );
next_block = _Heap_Block_at( the_block, the_size );
if ( !_Heap_Is_block_in( the_heap, next_block ) ||
(the_block->front_flag != next_block->back_flag) )
return( FALSE );
*size = the_size;
return( TRUE );
}

View File

@@ -0,0 +1,150 @@
/*
* Heap Handler
*
* COPYRIGHT (c) 1989-1998.
* On-Line Applications Research Corporation (OAR).
* Copyright assigned to U.S. Government, 1994.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <rtems/system.h>
#include <rtems/score/sysstate.h>
#include <rtems/score/heap.h>
/*PAGE
*
* _Heap_Walk
*
* This kernel routine walks the heap and verifies its correctness.
*
* Input parameters:
* the_heap - pointer to heap header
* source - a numeric indicator of the invoker of this routine
* do_dump - when TRUE print the information
*
* Output parameters: NONE
*/
#ifndef RTEMS_DEBUG
void _Heap_Walk(
Heap_Control *the_heap,
int source,
boolean do_dump
)
{
}
#else
#include <stdio.h>
#include <unistd.h>
void _Heap_Walk(
Heap_Control *the_heap,
int source,
boolean do_dump
)
{
Heap_Block *the_block = 0; /* avoid warnings */
Heap_Block *next_block = 0; /* avoid warnings */
int notdone = 1;
int error = 0;
int passes = 0;
/*
* We don't want to allow walking the heap until we have
* transferred control to the user task so we watch the
* system state.
*/
if ( !_System_state_Is_up( _System_state_Get() ) )
return;
the_block = the_heap->start;
if (do_dump == TRUE) {
printf("\nPASS: %d start @ 0x%p final 0x%p, first 0x%p last 0x%p\n",
source, the_heap->start, the_heap->final,
the_heap->first, the_heap->last
);
}
/*
* Handle the 1st block
*/
if (the_block->back_flag != HEAP_DUMMY_FLAG) {
printf("PASS: %d Back flag of 1st block isn't HEAP_DUMMY_FLAG\n", source);
error = 1;
}
while (notdone) {
passes++;
if (error && (passes > 10))
abort();
if (do_dump == TRUE) {
printf("PASS: %d Block @ 0x%p Back %d, Front %d",
source, the_block,
the_block->back_flag, the_block->front_flag);
if ( _Heap_Is_block_free(the_block) ) {
printf( " Prev 0x%p, Next 0x%p\n",
the_block->previous, the_block->next);
} else {
printf("\n");
}
}
/*
* Handle the last block
*/
if ( the_block->front_flag != HEAP_DUMMY_FLAG ) {
next_block = _Heap_Next_block(the_block);
if ( the_block->front_flag != next_block->back_flag ) {
error = 1;
printf("PASS: %d Front and back flags don't match\n", source);
printf(" Current Block (%p): Back - %d, Front - %d",
the_block, the_block->back_flag, the_block->front_flag);
if (do_dump == TRUE) {
if (_Heap_Is_block_free(the_block)) {
printf(" Prev 0x%p, Next 0x%p\n",
the_block->previous, the_block->next);
} else {
printf("\n");
}
} else {
printf("\n");
}
printf(" Next Block (%p): Back - %d, Front - %d",
next_block, next_block->back_flag, next_block->front_flag);
if (do_dump == TRUE) {
if (_Heap_Is_block_free(next_block)) {
printf(" Prev 0x%p, Next 0x%p\n",
the_block->previous, the_block->next);
} else {
printf("\n");
}
} else {
printf("\n");
}
}
}
if (the_block->front_flag == HEAP_DUMMY_FLAG)
notdone = 0;
else
the_block = next_block;
}
if (error)
abort();
}
#endif

View File

@@ -70,916 +70,3 @@ void _Thread_queue_Initialize(
}
}
#if 0
/*PAGE
*
* _Thread_queue_Enqueue
*
* This routine blocks a thread, places it on a thread, and optionally
* starts a timeout timer.
*
* Input parameters:
* the_thread_queue - pointer to threadq
* timeout - interval to wait
*
* Output parameters: NONE
*
* INTERRUPT LATENCY:
* only case
*/
void _Thread_queue_Enqueue(
Thread_queue_Control *the_thread_queue,
Watchdog_Interval timeout
)
{
Thread_Control *the_thread;
the_thread = _Thread_Executing;
#if defined(RTEMS_MULTIPROCESSING)
if ( _Thread_MP_Is_receive( the_thread ) && the_thread->receive_packet )
the_thread = _Thread_MP_Allocate_proxy( the_thread_queue->state );
else
#endif
_Thread_Set_state( the_thread, the_thread_queue->state );
if ( timeout ) {
_Watchdog_Initialize(
&the_thread->Timer,
_Thread_queue_Timeout,
the_thread->Object.id,
NULL
);
_Watchdog_Insert_ticks( &the_thread->Timer, timeout );
}
switch( the_thread_queue->discipline ) {
case THREAD_QUEUE_DISCIPLINE_FIFO:
_Thread_queue_Enqueue_fifo( the_thread_queue, the_thread, timeout );
break;
case THREAD_QUEUE_DISCIPLINE_PRIORITY:
_Thread_queue_Enqueue_priority( the_thread_queue, the_thread, timeout );
break;
}
}
/*PAGE
*
* _Thread_queue_Dequeue
*
* This routine removes a thread from the specified threadq. If the
* threadq discipline is FIFO, it unblocks a thread, and cancels its
* timeout timer. Priority discipline is processed elsewhere.
*
* Input parameters:
* the_thread_queue - pointer to threadq
*
* Output parameters:
* returns - thread dequeued or NULL
*
* INTERRUPT LATENCY:
* check sync
*/
Thread_Control *_Thread_queue_Dequeue(
Thread_queue_Control *the_thread_queue
)
{
Thread_Control *the_thread;
switch ( the_thread_queue->discipline ) {
case THREAD_QUEUE_DISCIPLINE_FIFO:
the_thread = _Thread_queue_Dequeue_fifo( the_thread_queue );
break;
case THREAD_QUEUE_DISCIPLINE_PRIORITY:
the_thread = _Thread_queue_Dequeue_priority( the_thread_queue );
break;
default: /* this is only to prevent warnings */
the_thread = NULL;
break;
}
return( the_thread );
}
/*PAGE
*
* _Thread_queue_Extract_with_proxy
*
* This routine extracts the_thread from the_thread_queue
* and insures that if there is a proxy for this task on
* another node, it is also dealt with.
*
* XXX
*/
boolean _Thread_queue_Extract_with_proxy(
Thread_Control *the_thread
)
{
States_Control state;
Objects_Classes the_class;
Thread_queue_Extract_callout proxy_extract_callout;
state = the_thread->current_state;
if ( _States_Is_waiting_on_thread_queue( state ) ) {
if ( _States_Is_waiting_for_rpc_reply( state ) &&
_States_Is_locally_blocked( state ) ) {
the_class = _Objects_Get_class( the_thread->Wait.id );
proxy_extract_callout = _Thread_queue_Extract_table[ the_class ];
if ( proxy_extract_callout )
(*proxy_extract_callout)( the_thread );
}
_Thread_queue_Extract( the_thread->Wait.queue, the_thread );
return TRUE;
}
return FALSE;
}
/*PAGE
*
* _Thread_queue_Extract
*
* This routine removes a specific thread from the specified threadq,
* deletes any timeout, and unblocks the thread.
*
* Input parameters:
* the_thread_queue - pointer to a threadq header
* the_thread - pointer to a thread control block
*
* Output parameters: NONE
*
* INTERRUPT LATENCY: NONE
*/
void _Thread_queue_Extract(
Thread_queue_Control *the_thread_queue,
Thread_Control *the_thread
)
{
switch ( the_thread_queue->discipline ) {
case THREAD_QUEUE_DISCIPLINE_FIFO:
_Thread_queue_Extract_fifo( the_thread_queue, the_thread );
break;
case THREAD_QUEUE_DISCIPLINE_PRIORITY:
_Thread_queue_Extract_priority( the_thread_queue, the_thread );
break;
}
}
/*PAGE
*
* _Thread_queue_Flush
*
* This kernel routine flushes the given thread queue.
*
* Input parameters:
* the_thread_queue - pointer to threadq to be flushed
* remote_extract_callout - pointer to routine which extracts a remote thread
* status - status to return to the thread
*
* Output parameters: NONE
*/
void _Thread_queue_Flush(
Thread_queue_Control *the_thread_queue,
Thread_queue_Flush_callout remote_extract_callout,
unsigned32 status
)
{
Thread_Control *the_thread;
while ( (the_thread = _Thread_queue_Dequeue( the_thread_queue )) ) {
#if defined(RTEMS_MULTIPROCESSING)
if ( !_Objects_Is_local_id( the_thread->Object.id ) )
( *remote_extract_callout )( the_thread );
else
#endif
the_thread->Wait.return_code = status;
}
}
/*PAGE
*
* _Thread_queue_First
*
* This routines returns a pointer to the first thread on the
* specified threadq.
*
* Input parameters:
* the_thread_queue - pointer to thread queue
*
* Output parameters:
* returns - first thread or NULL
*/
Thread_Control *_Thread_queue_First(
Thread_queue_Control *the_thread_queue
)
{
Thread_Control *the_thread;
switch ( the_thread_queue->discipline ) {
case THREAD_QUEUE_DISCIPLINE_FIFO:
the_thread = _Thread_queue_First_fifo( the_thread_queue );
break;
case THREAD_QUEUE_DISCIPLINE_PRIORITY:
the_thread = _Thread_queue_First_priority( the_thread_queue );
break;
default: /* this is only to prevent warnings */
the_thread = NULL;
break;
}
return the_thread;
}
/*PAGE
*
* _Thread_queue_Timeout
*
* This routine processes a thread which timeouts while waiting on
* a thread queue. It is called by the watchdog handler.
*
* Input parameters:
* id - thread id
*
* Output parameters: NONE
*/
void _Thread_queue_Timeout(
Objects_Id id,
void *ignored
)
{
Thread_Control *the_thread;
Thread_queue_Control *the_thread_queue;
Objects_Locations location;
the_thread = _Thread_Get( id, &location );
switch ( location ) {
case OBJECTS_ERROR:
case OBJECTS_REMOTE: /* impossible */
break;
case OBJECTS_LOCAL:
the_thread_queue = the_thread->Wait.queue;
/*
* If the_thread_queue is not synchronized, then it is either
* "nothing happened", "timeout", or "satisfied". If the_thread
* is the executing thread, then it is in the process of blocking
* and it is the thread which is responsible for the synchronization
* process.
*
* If it is not satisfied, then it is "nothing happened" and
* this is the "timeout" transition. After a request is satisfied,
* a timeout is not allowed to occur.
*/
if ( the_thread_queue->sync_state != THREAD_QUEUE_SYNCHRONIZED &&
_Thread_Is_executing( the_thread ) ) {
if ( the_thread_queue->sync_state != THREAD_QUEUE_SATISFIED )
the_thread_queue->sync_state = THREAD_QUEUE_TIMEOUT;
} else {
the_thread->Wait.return_code = the_thread->Wait.queue->timeout_status;
_Thread_queue_Extract( the_thread->Wait.queue, the_thread );
}
_Thread_Unnest_dispatch();
break;
}
}
/*PAGE
*
* _Thread_queue_Enqueue_fifo
*
* This routine blocks a thread, places it on a thread, and optionally
* starts a timeout timer.
*
* Input parameters:
* the_thread_queue - pointer to threadq
* the_thread - pointer to the thread to block
* timeout - interval to wait
*
* Output parameters: NONE
*
* INTERRUPT LATENCY:
* only case
*/
void _Thread_queue_Enqueue_fifo (
Thread_queue_Control *the_thread_queue,
Thread_Control *the_thread,
Watchdog_Interval timeout
)
{
ISR_Level level;
Thread_queue_States sync_state;
_ISR_Disable( level );
sync_state = the_thread_queue->sync_state;
the_thread_queue->sync_state = THREAD_QUEUE_SYNCHRONIZED;
switch ( sync_state ) {
case THREAD_QUEUE_SYNCHRONIZED:
/*
* This should never happen. It indicates that someone did not
* enter a thread queue critical section.
*/
break;
case THREAD_QUEUE_NOTHING_HAPPENED:
_Chain_Append_unprotected(
&the_thread_queue->Queues.Fifo,
&the_thread->Object.Node
);
_ISR_Enable( level );
return;
case THREAD_QUEUE_TIMEOUT:
the_thread->Wait.return_code = the_thread->Wait.queue->timeout_status;
_ISR_Enable( level );
break;
case THREAD_QUEUE_SATISFIED:
if ( _Watchdog_Is_active( &the_thread->Timer ) ) {
_Watchdog_Deactivate( &the_thread->Timer );
_ISR_Enable( level );
(void) _Watchdog_Remove( &the_thread->Timer );
} else
_ISR_Enable( level );
break;
}
/*
* Global objects with thread queue's should not be operated on from an
* ISR. But the sync code still must allow short timeouts to be processed
* correctly.
*/
_Thread_Unblock( the_thread );
#if defined(RTEMS_MULTIPROCESSING)
if ( !_Objects_Is_local_id( the_thread->Object.id ) )
_Thread_MP_Free_proxy( the_thread );
#endif
}
/*PAGE
*
* _Thread_queue_Dequeue_fifo
*
* This routine removes a thread from the specified threadq.
*
* Input parameters:
* the_thread_queue - pointer to threadq
*
* Output parameters:
* returns - thread dequeued or NULL
*
* INTERRUPT LATENCY:
* check sync
* FIFO
*/
Thread_Control *_Thread_queue_Dequeue_fifo(
Thread_queue_Control *the_thread_queue
)
{
ISR_Level level;
Thread_Control *the_thread;
_ISR_Disable( level );
if ( !_Chain_Is_empty( &the_thread_queue->Queues.Fifo ) ) {
the_thread = (Thread_Control *)
_Chain_Get_first_unprotected( &the_thread_queue->Queues.Fifo );
if ( !_Watchdog_Is_active( &the_thread->Timer ) ) {
_ISR_Enable( level );
_Thread_Unblock( the_thread );
} else {
_Watchdog_Deactivate( &the_thread->Timer );
_ISR_Enable( level );
(void) _Watchdog_Remove( &the_thread->Timer );
_Thread_Unblock( the_thread );
}
#if defined(RTEMS_MULTIPROCESSING)
if ( !_Objects_Is_local_id( the_thread->Object.id ) )
_Thread_MP_Free_proxy( the_thread );
#endif
return the_thread;
}
switch ( the_thread_queue->sync_state ) {
case THREAD_QUEUE_SYNCHRONIZED:
case THREAD_QUEUE_SATISFIED:
_ISR_Enable( level );
return NULL;
case THREAD_QUEUE_NOTHING_HAPPENED:
case THREAD_QUEUE_TIMEOUT:
the_thread_queue->sync_state = THREAD_QUEUE_SATISFIED;
_ISR_Enable( level );
return _Thread_Executing;
}
return NULL; /* this is only to prevent warnings */
}
/*PAGE
*
* _Thread_queue_Extract_fifo
*
* This routine removes a specific thread from the specified threadq,
* deletes any timeout, and unblocks the thread.
*
* Input parameters:
* the_thread_queue - pointer to a threadq header
* the_thread - pointer to the thread to block
*
* Output parameters: NONE
*
* INTERRUPT LATENCY:
* EXTRACT_FIFO
*/
void _Thread_queue_Extract_fifo(
Thread_queue_Control *the_thread_queue,
Thread_Control *the_thread
)
{
ISR_Level level;
_ISR_Disable( level );
if ( !_States_Is_waiting_on_thread_queue( the_thread->current_state ) ) {
_ISR_Enable( level );
return;
}
_Chain_Extract_unprotected( &the_thread->Object.Node );
if ( !_Watchdog_Is_active( &the_thread->Timer ) ) {
_ISR_Enable( level );
} else {
_Watchdog_Deactivate( &the_thread->Timer );
_ISR_Enable( level );
(void) _Watchdog_Remove( &the_thread->Timer );
}
_Thread_Unblock( the_thread );
#if defined(RTEMS_MULTIPROCESSING)
if ( !_Objects_Is_local_id( the_thread->Object.id ) )
_Thread_MP_Free_proxy( the_thread );
#endif
}
/*PAGE
*
* _Thread_queue_First_fifo
*
* This routines returns a pointer to the first thread on the
* specified threadq.
*
* Input parameters:
* the_thread_queue - pointer to threadq
*
* Output parameters:
* returns - first thread or NULL
*/
Thread_Control *_Thread_queue_First_fifo(
Thread_queue_Control *the_thread_queue
)
{
if ( !_Chain_Is_empty( &the_thread_queue->Queues.Fifo ) )
return (Thread_Control *) the_thread_queue->Queues.Fifo.first;
return NULL;
}
/*PAGE
*
* _Thread_queue_Enqueue_priority
*
* This routine blocks a thread, places it on a thread, and optionally
* starts a timeout timer.
*
* Input parameters:
* the_thread_queue - pointer to threadq
* thread - thread to insert
* timeout - timeout interval in ticks
*
* Output parameters: NONE
*
* INTERRUPT LATENCY:
* forward less than
* forward equal
*/
void _Thread_queue_Enqueue_priority(
Thread_queue_Control *the_thread_queue,
Thread_Control *the_thread,
Watchdog_Interval timeout
)
{
Priority_Control search_priority;
Thread_Control *search_thread;
ISR_Level level;
Chain_Control *header;
unsigned32 header_index;
Chain_Node *the_node;
Chain_Node *next_node;
Chain_Node *previous_node;
Chain_Node *search_node;
Priority_Control priority;
States_Control block_state;
Thread_queue_States sync_state;
_Chain_Initialize_empty( &the_thread->Wait.Block2n );
priority = the_thread->current_priority;
header_index = _Thread_queue_Header_number( priority );
header = &the_thread_queue->Queues.Priority[ header_index ];
block_state = the_thread_queue->state;
if ( _Thread_queue_Is_reverse_search( priority ) )
goto restart_reverse_search;
restart_forward_search:
search_priority = PRIORITY_MINIMUM - 1;
_ISR_Disable( level );
search_thread = (Thread_Control *) header->first;
while ( !_Chain_Is_tail( header, (Chain_Node *)search_thread ) ) {
search_priority = search_thread->current_priority;
if ( priority <= search_priority )
break;
#if ( CPU_UNROLL_ENQUEUE_PRIORITY == TRUE )
search_thread = (Thread_Control *) search_thread->Object.Node.next;
if ( _Chain_Is_tail( header, (Chain_Node *)search_thread ) )
break;
search_priority = search_thread->current_priority;
if ( priority <= search_priority )
break;
#endif
_ISR_Flash( level );
if ( !_States_Are_set( search_thread->current_state, block_state) ) {
_ISR_Enable( level );
goto restart_forward_search;
}
search_thread =
(Thread_Control *)search_thread->Object.Node.next;
}
if ( the_thread_queue->sync_state != THREAD_QUEUE_NOTHING_HAPPENED )
goto synchronize;
the_thread_queue->sync_state = THREAD_QUEUE_SYNCHRONIZED;
if ( priority == search_priority )
goto equal_priority;
search_node = (Chain_Node *) search_thread;
previous_node = search_node->previous;
the_node = (Chain_Node *) the_thread;
the_node->next = search_node;
the_node->previous = previous_node;
previous_node->next = the_node;
search_node->previous = the_node;
_ISR_Enable( level );
return;
restart_reverse_search:
search_priority = PRIORITY_MAXIMUM + 1;
_ISR_Disable( level );
search_thread = (Thread_Control *) header->last;
while ( !_Chain_Is_head( header, (Chain_Node *)search_thread ) ) {
search_priority = search_thread->current_priority;
if ( priority >= search_priority )
break;
#if ( CPU_UNROLL_ENQUEUE_PRIORITY == TRUE )
search_thread = (Thread_Control *) search_thread->Object.Node.previous;
if ( _Chain_Is_head( header, (Chain_Node *)search_thread ) )
break;
search_priority = search_thread->current_priority;
if ( priority >= search_priority )
break;
#endif
_ISR_Flash( level );
if ( !_States_Are_set( search_thread->current_state, block_state) ) {
_ISR_Enable( level );
goto restart_reverse_search;
}
search_thread = (Thread_Control *)
search_thread->Object.Node.previous;
}
if ( the_thread_queue->sync_state != THREAD_QUEUE_NOTHING_HAPPENED )
goto synchronize;
the_thread_queue->sync_state = THREAD_QUEUE_SYNCHRONIZED;
if ( priority == search_priority )
goto equal_priority;
search_node = (Chain_Node *) search_thread;
next_node = search_node->next;
the_node = (Chain_Node *) the_thread;
the_node->next = next_node;
the_node->previous = search_node;
search_node->next = the_node;
next_node->previous = the_node;
_ISR_Enable( level );
return;
equal_priority: /* add at end of priority group */
search_node = _Chain_Tail( &search_thread->Wait.Block2n );
previous_node = search_node->previous;
the_node = (Chain_Node *) the_thread;
the_node->next = search_node;
the_node->previous = previous_node;
previous_node->next = the_node;
search_node->previous = the_node;
_ISR_Enable( level );
return;
synchronize:
sync_state = the_thread_queue->sync_state;
the_thread_queue->sync_state = THREAD_QUEUE_SYNCHRONIZED;
switch ( sync_state ) {
case THREAD_QUEUE_SYNCHRONIZED:
/*
* This should never happen. It indicates that someone did not
* enter a thread queue critical section.
*/
break;
case THREAD_QUEUE_NOTHING_HAPPENED:
/*
* This should never happen. All of this was dealt with above.
*/
break;
case THREAD_QUEUE_TIMEOUT:
the_thread->Wait.return_code = the_thread->Wait.queue->timeout_status;
_ISR_Enable( level );
break;
case THREAD_QUEUE_SATISFIED:
if ( _Watchdog_Is_active( &the_thread->Timer ) ) {
_Watchdog_Deactivate( &the_thread->Timer );
_ISR_Enable( level );
(void) _Watchdog_Remove( &the_thread->Timer );
} else
_ISR_Enable( level );
break;
}
/*
* Global objects with thread queue's should not be operated on from an
* ISR. But the sync code still must allow short timeouts to be processed
* correctly.
*/
_Thread_Unblock( the_thread );
#if defined(RTEMS_MULTIPROCESSING)
if ( !_Objects_Is_local_id( the_thread->Object.id ) )
_Thread_MP_Free_proxy( the_thread );
#endif
}
/*PAGE
*
* _Thread_queue_Dequeue_priority
*
* This routine removes a thread from the specified PRIORITY based
* threadq, unblocks it, and cancels its timeout timer.
*
* Input parameters:
* the_thread_queue - pointer to thread queue
*
* Output parameters:
* returns - thread dequeued or NULL
*
* INTERRUPT LATENCY:
* only case
*/
Thread_Control *_Thread_queue_Dequeue_priority(
Thread_queue_Control *the_thread_queue
)
{
unsigned32 index;
ISR_Level level;
Thread_Control *the_thread = NULL; /* just to remove warnings */
Thread_Control *new_first_thread;
Chain_Node *new_first_node;
Chain_Node *new_second_node;
Chain_Node *last_node;
Chain_Node *next_node;
Chain_Node *previous_node;
_ISR_Disable( level );
for( index=0 ;
index < TASK_QUEUE_DATA_NUMBER_OF_PRIORITY_HEADERS ;
index++ ) {
if ( !_Chain_Is_empty( &the_thread_queue->Queues.Priority[ index ] ) ) {
the_thread = (Thread_Control *)
the_thread_queue->Queues.Priority[ index ].first;
goto dequeue;
}
}
switch ( the_thread_queue->sync_state ) {
case THREAD_QUEUE_SYNCHRONIZED:
case THREAD_QUEUE_SATISFIED:
_ISR_Enable( level );
return NULL;
case THREAD_QUEUE_NOTHING_HAPPENED:
case THREAD_QUEUE_TIMEOUT:
the_thread_queue->sync_state = THREAD_QUEUE_SATISFIED;
_ISR_Enable( level );
return _Thread_Executing;
}
dequeue:
new_first_node = the_thread->Wait.Block2n.first;
new_first_thread = (Thread_Control *) new_first_node;
next_node = the_thread->Object.Node.next;
previous_node = the_thread->Object.Node.previous;
if ( !_Chain_Is_empty( &the_thread->Wait.Block2n ) ) {
last_node = the_thread->Wait.Block2n.last;
new_second_node = new_first_node->next;
previous_node->next = new_first_node;
next_node->previous = new_first_node;
new_first_node->next = next_node;
new_first_node->previous = previous_node;
if ( !_Chain_Has_only_one_node( &the_thread->Wait.Block2n ) ) {
/* > two threads on 2-n */
new_second_node->previous =
_Chain_Head( &new_first_thread->Wait.Block2n );
new_first_thread->Wait.Block2n.first = new_second_node;
new_first_thread->Wait.Block2n.last = last_node;
last_node->next = _Chain_Tail( &new_first_thread->Wait.Block2n );
}
} else {
previous_node->next = next_node;
next_node->previous = previous_node;
}
if ( !_Watchdog_Is_active( &the_thread->Timer ) ) {
_ISR_Enable( level );
_Thread_Unblock( the_thread );
} else {
_Watchdog_Deactivate( &the_thread->Timer );
_ISR_Enable( level );
(void) _Watchdog_Remove( &the_thread->Timer );
_Thread_Unblock( the_thread );
}
#if defined(RTEMS_MULTIPROCESSING)
if ( !_Objects_Is_local_id( the_thread->Object.id ) )
_Thread_MP_Free_proxy( the_thread );
#endif
return( the_thread );
}
/*PAGE
*
* _Thread_queue_Extract_priority
*
* This routine removes a specific thread from the specified threadq,
* deletes any timeout, and unblocks the thread.
*
* Input parameters:
* the_thread_queue - pointer to a threadq header
* the_thread - pointer to a thread control block
*
* Output parameters: NONE
*
* INTERRUPT LATENCY:
* EXTRACT_PRIORITY
*/
void _Thread_queue_Extract_priority(
Thread_queue_Control *the_thread_queue,
Thread_Control *the_thread
)
{
ISR_Level level;
Chain_Node *the_node;
Chain_Node *next_node;
Chain_Node *previous_node;
Thread_Control *new_first_thread;
Chain_Node *new_first_node;
Chain_Node *new_second_node;
Chain_Node *last_node;
the_node = (Chain_Node *) the_thread;
_ISR_Disable( level );
if ( _States_Is_waiting_on_thread_queue( the_thread->current_state ) ) {
next_node = the_node->next;
previous_node = the_node->previous;
if ( !_Chain_Is_empty( &the_thread->Wait.Block2n ) ) {
new_first_node = the_thread->Wait.Block2n.first;
new_first_thread = (Thread_Control *) new_first_node;
last_node = the_thread->Wait.Block2n.last;
new_second_node = new_first_node->next;
previous_node->next = new_first_node;
next_node->previous = new_first_node;
new_first_node->next = next_node;
new_first_node->previous = previous_node;
if ( !_Chain_Has_only_one_node( &the_thread->Wait.Block2n ) ) {
/* > two threads on 2-n */
new_second_node->previous =
_Chain_Head( &new_first_thread->Wait.Block2n );
new_first_thread->Wait.Block2n.first = new_second_node;
new_first_thread->Wait.Block2n.last = last_node;
last_node->next = _Chain_Tail( &new_first_thread->Wait.Block2n );
}
} else {
previous_node->next = next_node;
next_node->previous = previous_node;
}
if ( !_Watchdog_Is_active( &the_thread->Timer ) ) {
_ISR_Enable( level );
_Thread_Unblock( the_thread );
} else {
_Watchdog_Deactivate( &the_thread->Timer );
_ISR_Enable( level );
(void) _Watchdog_Remove( &the_thread->Timer );
_Thread_Unblock( the_thread );
}
#if defined(RTEMS_MULTIPROCESSING)
if ( !_Objects_Is_local_id( the_thread->Object.id ) )
_Thread_MP_Free_proxy( the_thread );
#endif
}
else
_ISR_Enable( level );
}
/*PAGE
*
* _Thread_queue_First_priority
*
* This routines returns a pointer to the first thread on the
* specified threadq.
*
* Input parameters:
* the_thread_queue - pointer to thread queue
*
* Output parameters:
* returns - first thread or NULL
*/
Thread_Control *_Thread_queue_First_priority (
Thread_queue_Control *the_thread_queue
)
{
unsigned32 index;
for( index=0 ;
index < TASK_QUEUE_DATA_NUMBER_OF_PRIORITY_HEADERS ;
index++ ) {
if ( !_Chain_Is_empty( &the_thread_queue->Queues.Priority[ index ] ) )
return (Thread_Control *)
the_thread_queue->Queues.Priority[ index ].first;
}
return NULL;
}
#endif

View File

@@ -0,0 +1,65 @@
/*
* Time of Day (TOD) Handler
*
*
* COPYRIGHT (c) 1989-1998.
* On-Line Applications Research Corporation (OAR).
* Copyright assigned to U.S. Government, 1994.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <rtems/system.h>
#include <rtems/score/object.h>
#include <rtems/score/thread.h>
#include <rtems/score/tod.h>
#include <rtems/score/watchdog.h>
/*PAGE
*
* _TOD_To_seconds
*
* This routine returns the seconds from the epoch until the
* current date and time.
*
* Input parameters:
* the_tod - pointer to the time and date structure
*
* Output parameters:
* returns - seconds since epoch until the_tod
*/
unsigned32 _TOD_To_seconds(
TOD_Control *the_tod
)
{
unsigned32 time;
unsigned32 year_mod_4;
time = the_tod->day - 1;
year_mod_4 = the_tod->year & 3;
if ( year_mod_4 == 0 )
time += _TOD_Days_to_date[ 1 ][ the_tod->month ];
else
time += _TOD_Days_to_date[ 0 ][ the_tod->month ];
time += ( (the_tod->year - TOD_BASE_YEAR) / 4 ) *
( (TOD_DAYS_PER_YEAR * 4) + 1);
time += _TOD_Days_since_last_leap_year[ year_mod_4 ];
time *= TOD_SECONDS_PER_DAY;
time += ((the_tod->hour * TOD_MINUTES_PER_HOUR) + the_tod->minute)
* TOD_SECONDS_PER_MINUTE;
time += the_tod->second;
return( time );
}

View File

@@ -0,0 +1,64 @@
/*
* Time of Day (TOD) Handler
*
*
* COPYRIGHT (c) 1989-1998.
* On-Line Applications Research Corporation (OAR).
* Copyright assigned to U.S. Government, 1994.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <rtems/system.h>
#include <rtems/score/object.h>
#include <rtems/score/thread.h>
#include <rtems/score/tod.h>
#include <rtems/score/watchdog.h>
/*PAGE
*
* _TOD_Validate
*
* This kernel routine checks the validity of a date and time structure.
*
* Input parameters:
* the_tod - pointer to a time and date structure
*
* Output parameters:
* TRUE - if the date, time, and tick are valid
* FALSE - if the the_tod is invalid
*
* NOTE: This routine only works for leap-years through 2099.
*/
boolean _TOD_Validate(
TOD_Control *the_tod
)
{
unsigned32 days_in_month;
if ((the_tod->ticks >= _TOD_Ticks_per_second) ||
(the_tod->second >= TOD_SECONDS_PER_MINUTE) ||
(the_tod->minute >= TOD_MINUTES_PER_HOUR) ||
(the_tod->hour >= TOD_HOURS_PER_DAY) ||
(the_tod->month == 0) ||
(the_tod->month > TOD_MONTHS_PER_YEAR) ||
(the_tod->year < TOD_BASE_YEAR) ||
(the_tod->day == 0) )
return FALSE;
if ( (the_tod->year % 4) == 0 )
days_in_month = _TOD_Days_per_month[ 1 ][ the_tod->month ];
else
days_in_month = _TOD_Days_per_month[ 0 ][ the_tod->month ];
if ( the_tod->day > days_in_month )
return FALSE;
return TRUE;
}

View File

@@ -58,181 +58,3 @@ void _TOD_Handler_initialization(
_TOD_Is_set = FALSE;
_TOD_Activate( _TOD_Ticks_per_second );
}
/*PAGE
*
* _TOD_Set
*
* This rountine sets the current date and time with the specified
* new date and time structure.
*
* Input parameters:
* the_tod - pointer to the time and date structure
* seconds_since_epoch - seconds since system epoch
*
* Output parameters: NONE
*/
void _TOD_Set(
TOD_Control *the_tod,
Watchdog_Interval seconds_since_epoch
)
{
Watchdog_Interval ticks_until_next_second;
_Thread_Disable_dispatch();
_TOD_Deactivate();
if ( seconds_since_epoch < _TOD_Seconds_since_epoch )
_Watchdog_Adjust_seconds( WATCHDOG_BACKWARD,
_TOD_Seconds_since_epoch - seconds_since_epoch );
else
_Watchdog_Adjust_seconds( WATCHDOG_FORWARD,
seconds_since_epoch - _TOD_Seconds_since_epoch );
ticks_until_next_second = _TOD_Ticks_per_second;
if ( ticks_until_next_second > _TOD_Current.ticks )
ticks_until_next_second -= _TOD_Current.ticks;
_TOD_Current = *the_tod;
_TOD_Seconds_since_epoch = seconds_since_epoch;
_TOD_Is_set = TRUE;
_TOD_Activate( ticks_until_next_second );
_Thread_Enable_dispatch();
}
/*PAGE
*
* _TOD_Validate
*
* This kernel routine checks the validity of a date and time structure.
*
* Input parameters:
* the_tod - pointer to a time and date structure
*
* Output parameters:
* TRUE - if the date, time, and tick are valid
* FALSE - if the the_tod is invalid
*
* NOTE: This routine only works for leap-years through 2099.
*/
boolean _TOD_Validate(
TOD_Control *the_tod
)
{
unsigned32 days_in_month;
if ((the_tod->ticks >= _TOD_Ticks_per_second) ||
(the_tod->second >= TOD_SECONDS_PER_MINUTE) ||
(the_tod->minute >= TOD_MINUTES_PER_HOUR) ||
(the_tod->hour >= TOD_HOURS_PER_DAY) ||
(the_tod->month == 0) ||
(the_tod->month > TOD_MONTHS_PER_YEAR) ||
(the_tod->year < TOD_BASE_YEAR) ||
(the_tod->day == 0) )
return FALSE;
if ( (the_tod->year % 4) == 0 )
days_in_month = _TOD_Days_per_month[ 1 ][ the_tod->month ];
else
days_in_month = _TOD_Days_per_month[ 0 ][ the_tod->month ];
if ( the_tod->day > days_in_month )
return FALSE;
return TRUE;
}
/*PAGE
*
* _TOD_To_seconds
*
* This routine returns the seconds from the epoch until the
* current date and time.
*
* Input parameters:
* the_tod - pointer to the time and date structure
*
* Output parameters:
* returns - seconds since epoch until the_tod
*/
unsigned32 _TOD_To_seconds(
TOD_Control *the_tod
)
{
unsigned32 time;
unsigned32 year_mod_4;
time = the_tod->day - 1;
year_mod_4 = the_tod->year & 3;
if ( year_mod_4 == 0 )
time += _TOD_Days_to_date[ 1 ][ the_tod->month ];
else
time += _TOD_Days_to_date[ 0 ][ the_tod->month ];
time += ( (the_tod->year - TOD_BASE_YEAR) / 4 ) *
( (TOD_DAYS_PER_YEAR * 4) + 1);
time += _TOD_Days_since_last_leap_year[ year_mod_4 ];
time *= TOD_SECONDS_PER_DAY;
time += ((the_tod->hour * TOD_MINUTES_PER_HOUR) + the_tod->minute)
* TOD_SECONDS_PER_MINUTE;
time += the_tod->second;
return( time );
}
/*PAGE
*
* _TOD_Tickle
*
* This routine updates the calendar time and tickles the
* per second watchdog timer chain.
*
* Input parameters:
* ignored - this parameter is ignored
*
* Output parameters: NONE
*
* NOTE: This routine only works for leap-years through 2099.
*/
void _TOD_Tickle(
Objects_Id id,
void *ignored
)
{
unsigned32 leap;
_TOD_Current.ticks = 0;
++_TOD_Seconds_since_epoch;
if ( ++_TOD_Current.second >= TOD_SECONDS_PER_MINUTE ) {
_TOD_Current.second = 0;
if ( ++_TOD_Current.minute >= TOD_MINUTES_PER_HOUR ) {
_TOD_Current.minute = 0;
if ( ++_TOD_Current.hour >= TOD_HOURS_PER_DAY ) {
_TOD_Current.hour = 0;
if ( _TOD_Current.year & 0x3 ) leap = 0;
else leap = 1;
if ( ++_TOD_Current.day >
_TOD_Days_per_month[ leap ][ _TOD_Current.month ]) {
_TOD_Current.day = 1;
if ( ++_TOD_Current.month > TOD_MONTHS_PER_YEAR ) {
_TOD_Current.month = 1;
_TOD_Current.year++;
}
}
}
}
}
_Watchdog_Tickle_seconds();
_Watchdog_Insert_ticks( &_TOD_Seconds_watchdog, _TOD_Ticks_per_second );
}

View File

@@ -0,0 +1,64 @@
/*
* Time of Day (TOD) Handler
*
*
* COPYRIGHT (c) 1989-1998.
* On-Line Applications Research Corporation (OAR).
* Copyright assigned to U.S. Government, 1994.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <rtems/system.h>
#include <rtems/score/object.h>
#include <rtems/score/thread.h>
#include <rtems/score/tod.h>
#include <rtems/score/watchdog.h>
/*PAGE
*
* _TOD_Set
*
* This rountine sets the current date and time with the specified
* new date and time structure.
*
* Input parameters:
* the_tod - pointer to the time and date structure
* seconds_since_epoch - seconds since system epoch
*
* Output parameters: NONE
*/
void _TOD_Set(
TOD_Control *the_tod,
Watchdog_Interval seconds_since_epoch
)
{
Watchdog_Interval ticks_until_next_second;
_Thread_Disable_dispatch();
_TOD_Deactivate();
if ( seconds_since_epoch < _TOD_Seconds_since_epoch )
_Watchdog_Adjust_seconds( WATCHDOG_BACKWARD,
_TOD_Seconds_since_epoch - seconds_since_epoch );
else
_Watchdog_Adjust_seconds( WATCHDOG_FORWARD,
seconds_since_epoch - _TOD_Seconds_since_epoch );
ticks_until_next_second = _TOD_Ticks_per_second;
if ( ticks_until_next_second > _TOD_Current.ticks )
ticks_until_next_second -= _TOD_Current.ticks;
_TOD_Current = *the_tod;
_TOD_Seconds_since_epoch = seconds_since_epoch;
_TOD_Is_set = TRUE;
_TOD_Activate( ticks_until_next_second );
_Thread_Enable_dispatch();
}

View File

@@ -0,0 +1,68 @@
/*
* Time of Day (TOD) Handler
*
*
* COPYRIGHT (c) 1989-1998.
* On-Line Applications Research Corporation (OAR).
* Copyright assigned to U.S. Government, 1994.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <rtems/system.h>
#include <rtems/score/object.h>
#include <rtems/score/thread.h>
#include <rtems/score/tod.h>
#include <rtems/score/watchdog.h>
/*PAGE
*
* _TOD_Tickle
*
* This routine updates the calendar time and tickles the
* per second watchdog timer chain.
*
* Input parameters:
* ignored - this parameter is ignored
*
* Output parameters: NONE
*
* NOTE: This routine only works for leap-years through 2099.
*/
void _TOD_Tickle(
Objects_Id id,
void *ignored
)
{
unsigned32 leap;
_TOD_Current.ticks = 0;
++_TOD_Seconds_since_epoch;
if ( ++_TOD_Current.second >= TOD_SECONDS_PER_MINUTE ) {
_TOD_Current.second = 0;
if ( ++_TOD_Current.minute >= TOD_MINUTES_PER_HOUR ) {
_TOD_Current.minute = 0;
if ( ++_TOD_Current.hour >= TOD_HOURS_PER_DAY ) {
_TOD_Current.hour = 0;
if ( _TOD_Current.year & 0x3 ) leap = 0;
else leap = 1;
if ( ++_TOD_Current.day >
_TOD_Days_per_month[ leap ][ _TOD_Current.month ]) {
_TOD_Current.day = 1;
if ( ++_TOD_Current.month > TOD_MONTHS_PER_YEAR ) {
_TOD_Current.month = 1;
_TOD_Current.year++;
}
}
}
}
}
_Watchdog_Tickle_seconds();
_Watchdog_Insert_ticks( &_TOD_Seconds_watchdog, _TOD_Ticks_per_second );
}

View File

@@ -0,0 +1,65 @@
/*
* Time of Day (TOD) Handler
*
*
* COPYRIGHT (c) 1989-1998.
* On-Line Applications Research Corporation (OAR).
* Copyright assigned to U.S. Government, 1994.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <rtems/system.h>
#include <rtems/score/object.h>
#include <rtems/score/thread.h>
#include <rtems/score/tod.h>
#include <rtems/score/watchdog.h>
/*PAGE
*
* _TOD_To_seconds
*
* This routine returns the seconds from the epoch until the
* current date and time.
*
* Input parameters:
* the_tod - pointer to the time and date structure
*
* Output parameters:
* returns - seconds since epoch until the_tod
*/
unsigned32 _TOD_To_seconds(
TOD_Control *the_tod
)
{
unsigned32 time;
unsigned32 year_mod_4;
time = the_tod->day - 1;
year_mod_4 = the_tod->year & 3;
if ( year_mod_4 == 0 )
time += _TOD_Days_to_date[ 1 ][ the_tod->month ];
else
time += _TOD_Days_to_date[ 0 ][ the_tod->month ];
time += ( (the_tod->year - TOD_BASE_YEAR) / 4 ) *
( (TOD_DAYS_PER_YEAR * 4) + 1);
time += _TOD_Days_since_last_leap_year[ year_mod_4 ];
time *= TOD_SECONDS_PER_DAY;
time += ((the_tod->hour * TOD_MINUTES_PER_HOUR) + the_tod->minute)
* TOD_SECONDS_PER_MINUTE;
time += the_tod->second;
return( time );
}

View File

@@ -0,0 +1,64 @@
/*
* Time of Day (TOD) Handler
*
*
* COPYRIGHT (c) 1989-1998.
* On-Line Applications Research Corporation (OAR).
* Copyright assigned to U.S. Government, 1994.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <rtems/system.h>
#include <rtems/score/object.h>
#include <rtems/score/thread.h>
#include <rtems/score/tod.h>
#include <rtems/score/watchdog.h>
/*PAGE
*
* _TOD_Validate
*
* This kernel routine checks the validity of a date and time structure.
*
* Input parameters:
* the_tod - pointer to a time and date structure
*
* Output parameters:
* TRUE - if the date, time, and tick are valid
* FALSE - if the the_tod is invalid
*
* NOTE: This routine only works for leap-years through 2099.
*/
boolean _TOD_Validate(
TOD_Control *the_tod
)
{
unsigned32 days_in_month;
if ((the_tod->ticks >= _TOD_Ticks_per_second) ||
(the_tod->second >= TOD_SECONDS_PER_MINUTE) ||
(the_tod->minute >= TOD_MINUTES_PER_HOUR) ||
(the_tod->hour >= TOD_HOURS_PER_DAY) ||
(the_tod->month == 0) ||
(the_tod->month > TOD_MONTHS_PER_YEAR) ||
(the_tod->year < TOD_BASE_YEAR) ||
(the_tod->day == 0) )
return FALSE;
if ( (the_tod->year % 4) == 0 )
days_in_month = _TOD_Days_per_month[ 1 ][ the_tod->month ];
else
days_in_month = _TOD_Days_per_month[ 0 ][ the_tod->month ];
if ( the_tod->day > days_in_month )
return FALSE;
return TRUE;
}

View File

@@ -92,447 +92,3 @@ unsigned32 _Heap_Initialize(
return ( the_size - HEAP_BLOCK_USED_OVERHEAD );
}
/*PAGE
*
* _Heap_Extend
*
* This routine grows the_heap memory area using the size bytes which
* begin at starting_address.
*
* Input parameters:
* the_heap - pointer to heap header.
* starting_address - pointer to the memory area.
* size - size in bytes of the memory block to allocate.
*
* Output parameters:
* *amount_extended - amount of memory added to the_heap
*/
Heap_Extend_status _Heap_Extend(
Heap_Control *the_heap,
void *starting_address,
unsigned32 size,
unsigned32 *amount_extended
)
{
Heap_Block *the_block;
unsigned32 *p;
/*
* The overhead was taken from the original heap memory.
*/
Heap_Block *old_final;
Heap_Block *new_final;
/*
* There are five possibilities for the location of starting
* address:
*
* 1. non-contiguous lower address (NOT SUPPORTED)
* 2. contiguous lower address (NOT SUPPORTED)
* 3. in the heap (ERROR)
* 4. contiguous higher address (SUPPORTED)
* 5. non-contiguous higher address (NOT SUPPORTED)
*
* As noted, this code only supports (4).
*/
if ( starting_address >= (void *) the_heap->start && /* case 3 */
starting_address <= (void *) the_heap->final
)
return HEAP_EXTEND_ERROR;
if ( starting_address < (void *) the_heap->start ) { /* cases 1 and 2 */
return HEAP_EXTEND_NOT_IMPLEMENTED; /* cases 1 and 2 */
} else { /* cases 4 and 5 */
the_block = (Heap_Block *)
_Addresses_Subtract_offset( starting_address, HEAP_OVERHEAD );
if ( the_block != the_heap->final )
return HEAP_EXTEND_NOT_IMPLEMENTED; /* case 5 */
}
/*
* Currently only case 4 should make it to this point.
* The basic trick is to make the extend area look like a used
* block and free it.
*/
*amount_extended = size;
old_final = the_heap->final;
new_final = _Addresses_Add_offset( old_final, size );
/* SAME AS: _Addresses_Add_offset( starting_address, size-HEAP_OVERHEAD ); */
the_heap->final = new_final;
old_final->front_flag =
new_final->back_flag = _Heap_Build_flag( size, HEAP_BLOCK_USED );
new_final->front_flag = HEAP_DUMMY_FLAG;
/*
* Must pass in address of "user" area
* So add in the offset field.
*/
p = (unsigned32 *) &old_final->next;
*p = sizeof(unsigned32);
p++;
_Heap_Free( the_heap, p );
return HEAP_EXTEND_SUCCESSFUL;
}
/*PAGE
*
* _Heap_Allocate
*
* This kernel routine allocates the requested size of memory
* from the specified heap.
*
* Input parameters:
* the_heap - pointer to heap header.
* size - size in bytes of the memory block to allocate.
*
* Output parameters:
* returns - starting address of memory block allocated
*/
void *_Heap_Allocate(
Heap_Control *the_heap,
unsigned32 size
)
{
unsigned32 excess;
unsigned32 the_size;
Heap_Block *the_block;
Heap_Block *next_block;
Heap_Block *temporary_block;
void *ptr;
unsigned32 offset;
excess = size % the_heap->page_size;
the_size = size + the_heap->page_size + HEAP_BLOCK_USED_OVERHEAD;
if ( excess )
the_size += the_heap->page_size - excess;
if ( the_size < sizeof( Heap_Block ) )
the_size = sizeof( Heap_Block );
for ( the_block = the_heap->first;
;
the_block = the_block->next ) {
if ( the_block == _Heap_Tail( the_heap ) )
return( NULL );
if ( the_block->front_flag >= the_size )
break;
}
if ( (the_block->front_flag - the_size) >
(the_heap->page_size + HEAP_BLOCK_USED_OVERHEAD) ) {
the_block->front_flag -= the_size;
next_block = _Heap_Next_block( the_block );
next_block->back_flag = the_block->front_flag;
temporary_block = _Heap_Block_at( next_block, the_size );
temporary_block->back_flag =
next_block->front_flag = _Heap_Build_flag( the_size,
HEAP_BLOCK_USED );
ptr = _Heap_Start_of_user_area( next_block );
} else {
next_block = _Heap_Next_block( the_block );
next_block->back_flag = _Heap_Build_flag( the_block->front_flag,
HEAP_BLOCK_USED );
the_block->front_flag = next_block->back_flag;
the_block->next->previous = the_block->previous;
the_block->previous->next = the_block->next;
ptr = _Heap_Start_of_user_area( the_block );
}
/*
* round ptr up to a multiple of page size
* Have to save the bump amount in the buffer so that free can figure it out
*/
offset = the_heap->page_size - (((unsigned32) ptr) & (the_heap->page_size - 1));
ptr = _Addresses_Add_offset( ptr, offset );
*(((unsigned32 *) ptr) - 1) = offset;
#ifdef RTEMS_DEBUG
{
unsigned32 ptr_u32;
ptr_u32 = (unsigned32) ptr;
if (ptr_u32 & (the_heap->page_size - 1))
abort();
}
#endif
return ptr;
}
/*PAGE
*
* _Heap_Size_of_user_area
*
* This kernel routine returns the size of the memory area
* given heap block.
*
* Input parameters:
* the_heap - pointer to heap header
* starting_address - starting address of the memory block to free.
* size - pointer to size of area
*
* Output parameters:
* size - size of area filled in
* TRUE - if starting_address is valid heap address
* FALSE - if starting_address is invalid heap address
*/
boolean _Heap_Size_of_user_area(
Heap_Control *the_heap,
void *starting_address,
unsigned32 *size
)
{
Heap_Block *the_block;
Heap_Block *next_block;
unsigned32 the_size;
the_block = _Heap_User_block_at( starting_address );
if ( !_Heap_Is_block_in( the_heap, the_block ) ||
_Heap_Is_block_free( the_block ) )
return( FALSE );
the_size = _Heap_Block_size( the_block );
next_block = _Heap_Block_at( the_block, the_size );
if ( !_Heap_Is_block_in( the_heap, next_block ) ||
(the_block->front_flag != next_block->back_flag) )
return( FALSE );
*size = the_size;
return( TRUE );
}
/*PAGE
*
* _Heap_Free
*
* This kernel routine returns the memory designated by the
* given heap and given starting address to the memory pool.
*
* Input parameters:
* the_heap - pointer to heap header
* starting_address - starting address of the memory block to free.
*
* Output parameters:
* TRUE - if starting_address is valid heap address
* FALSE - if starting_address is invalid heap address
*/
boolean _Heap_Free(
Heap_Control *the_heap,
void *starting_address
)
{
Heap_Block *the_block;
Heap_Block *next_block;
Heap_Block *new_next_block;
Heap_Block *previous_block;
Heap_Block *temporary_block;
unsigned32 the_size;
the_block = _Heap_User_block_at( starting_address );
if ( !_Heap_Is_block_in( the_heap, the_block ) ||
_Heap_Is_block_free( the_block ) ) {
return( FALSE );
}
the_size = _Heap_Block_size( the_block );
next_block = _Heap_Block_at( the_block, the_size );
if ( !_Heap_Is_block_in( the_heap, next_block ) ||
(the_block->front_flag != next_block->back_flag) ) {
return( FALSE );
}
if ( _Heap_Is_previous_block_free( the_block ) ) {
previous_block = _Heap_Previous_block( the_block );
if ( !_Heap_Is_block_in( the_heap, previous_block ) ) {
return( FALSE );
}
if ( _Heap_Is_block_free( next_block ) ) { /* coalesce both */
previous_block->front_flag += next_block->front_flag + the_size;
temporary_block = _Heap_Next_block( previous_block );
temporary_block->back_flag = previous_block->front_flag;
next_block->next->previous = next_block->previous;
next_block->previous->next = next_block->next;
}
else { /* coalesce prev */
previous_block->front_flag =
next_block->back_flag = previous_block->front_flag + the_size;
}
}
else if ( _Heap_Is_block_free( next_block ) ) { /* coalesce next */
the_block->front_flag = the_size + next_block->front_flag;
new_next_block = _Heap_Next_block( the_block );
new_next_block->back_flag = the_block->front_flag;
the_block->next = next_block->next;
the_block->previous = next_block->previous;
next_block->previous->next = the_block;
next_block->next->previous = the_block;
if (the_heap->first == next_block)
the_heap->first = the_block;
}
else { /* no coalesce */
next_block->back_flag =
the_block->front_flag = the_size;
the_block->previous = _Heap_Head( the_heap );
the_block->next = the_heap->first;
the_heap->first = the_block;
the_block->next->previous = the_block;
}
return( TRUE );
}
/*PAGE
*
* _Heap_Walk
*
* This kernel routine walks the heap and verifies its correctness.
*
* Input parameters:
* the_heap - pointer to heap header
* source - a numeric indicator of the invoker of this routine
* do_dump - when TRUE print the information
*
* Output parameters: NONE
*/
#ifndef RTEMS_DEBUG
void _Heap_Walk(
Heap_Control *the_heap,
int source,
boolean do_dump
)
{
}
#else
#include <stdio.h>
#include <unistd.h>
void _Heap_Walk(
Heap_Control *the_heap,
int source,
boolean do_dump
)
{
Heap_Block *the_block = 0; /* avoid warnings */
Heap_Block *next_block = 0; /* avoid warnings */
int notdone = 1;
int error = 0;
int passes = 0;
/*
* We don't want to allow walking the heap until we have
* transferred control to the user task so we watch the
* system state.
*/
if ( !_System_state_Is_up( _System_state_Get() ) )
return;
the_block = the_heap->start;
if (do_dump == TRUE) {
printf("\nPASS: %d start @ 0x%p final 0x%p, first 0x%p last 0x%p\n",
source, the_heap->start, the_heap->final,
the_heap->first, the_heap->last
);
}
/*
* Handle the 1st block
*/
if (the_block->back_flag != HEAP_DUMMY_FLAG) {
printf("PASS: %d Back flag of 1st block isn't HEAP_DUMMY_FLAG\n", source);
error = 1;
}
while (notdone) {
passes++;
if (error && (passes > 10))
abort();
if (do_dump == TRUE) {
printf("PASS: %d Block @ 0x%p Back %d, Front %d",
source, the_block,
the_block->back_flag, the_block->front_flag);
if ( _Heap_Is_block_free(the_block) ) {
printf( " Prev 0x%p, Next 0x%p\n",
the_block->previous, the_block->next);
} else {
printf("\n");
}
}
/*
* Handle the last block
*/
if ( the_block->front_flag != HEAP_DUMMY_FLAG ) {
next_block = _Heap_Next_block(the_block);
if ( the_block->front_flag != next_block->back_flag ) {
error = 1;
printf("PASS: %d Front and back flags don't match\n", source);
printf(" Current Block (%p): Back - %d, Front - %d",
the_block, the_block->back_flag, the_block->front_flag);
if (do_dump == TRUE) {
if (_Heap_Is_block_free(the_block)) {
printf(" Prev 0x%p, Next 0x%p\n",
the_block->previous, the_block->next);
} else {
printf("\n");
}
} else {
printf("\n");
}
printf(" Next Block (%p): Back - %d, Front - %d",
next_block, next_block->back_flag, next_block->front_flag);
if (do_dump == TRUE) {
if (_Heap_Is_block_free(next_block)) {
printf(" Prev 0x%p, Next 0x%p\n",
the_block->previous, the_block->next);
} else {
printf("\n");
}
} else {
printf("\n");
}
}
}
if (the_block->front_flag == HEAP_DUMMY_FLAG)
notdone = 0;
else
the_block = next_block;
}
if (error)
abort();
}
#endif

View File

@@ -0,0 +1,107 @@
/*
* Heap Handler
*
* COPYRIGHT (c) 1989-1998.
* On-Line Applications Research Corporation (OAR).
* Copyright assigned to U.S. Government, 1994.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <rtems/system.h>
#include <rtems/score/sysstate.h>
#include <rtems/score/heap.h>
/*PAGE
*
* _Heap_Allocate
*
* This kernel routine allocates the requested size of memory
* from the specified heap.
*
* Input parameters:
* the_heap - pointer to heap header.
* size - size in bytes of the memory block to allocate.
*
* Output parameters:
* returns - starting address of memory block allocated
*/
void *_Heap_Allocate(
Heap_Control *the_heap,
unsigned32 size
)
{
unsigned32 excess;
unsigned32 the_size;
Heap_Block *the_block;
Heap_Block *next_block;
Heap_Block *temporary_block;
void *ptr;
unsigned32 offset;
excess = size % the_heap->page_size;
the_size = size + the_heap->page_size + HEAP_BLOCK_USED_OVERHEAD;
if ( excess )
the_size += the_heap->page_size - excess;
if ( the_size < sizeof( Heap_Block ) )
the_size = sizeof( Heap_Block );
for ( the_block = the_heap->first;
;
the_block = the_block->next ) {
if ( the_block == _Heap_Tail( the_heap ) )
return( NULL );
if ( the_block->front_flag >= the_size )
break;
}
if ( (the_block->front_flag - the_size) >
(the_heap->page_size + HEAP_BLOCK_USED_OVERHEAD) ) {
the_block->front_flag -= the_size;
next_block = _Heap_Next_block( the_block );
next_block->back_flag = the_block->front_flag;
temporary_block = _Heap_Block_at( next_block, the_size );
temporary_block->back_flag =
next_block->front_flag = _Heap_Build_flag( the_size,
HEAP_BLOCK_USED );
ptr = _Heap_Start_of_user_area( next_block );
} else {
next_block = _Heap_Next_block( the_block );
next_block->back_flag = _Heap_Build_flag( the_block->front_flag,
HEAP_BLOCK_USED );
the_block->front_flag = next_block->back_flag;
the_block->next->previous = the_block->previous;
the_block->previous->next = the_block->next;
ptr = _Heap_Start_of_user_area( the_block );
}
/*
* round ptr up to a multiple of page size
* Have to save the bump amount in the buffer so that free can figure it out
*/
offset = the_heap->page_size - (((unsigned32) ptr) & (the_heap->page_size - 1));
ptr = _Addresses_Add_offset( ptr, offset );
*(((unsigned32 *) ptr) - 1) = offset;
#ifdef RTEMS_DEBUG
{
unsigned32 ptr_u32;
ptr_u32 = (unsigned32) ptr;
if (ptr_u32 & (the_heap->page_size - 1))
abort();
}
#endif
return ptr;
}

View File

@@ -0,0 +1,113 @@
/*
* Heap Handler
*
* COPYRIGHT (c) 1989-1998.
* On-Line Applications Research Corporation (OAR).
* Copyright assigned to U.S. Government, 1994.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <rtems/system.h>
#include <rtems/score/sysstate.h>
#include <rtems/score/heap.h>
/*PAGE
*
* _Heap_Extend
*
* This routine grows the_heap memory area using the size bytes which
* begin at starting_address.
*
* Input parameters:
* the_heap - pointer to heap header.
* starting_address - pointer to the memory area.
* size - size in bytes of the memory block to allocate.
*
* Output parameters:
* *amount_extended - amount of memory added to the_heap
*/
Heap_Extend_status _Heap_Extend(
Heap_Control *the_heap,
void *starting_address,
unsigned32 size,
unsigned32 *amount_extended
)
{
Heap_Block *the_block;
unsigned32 *p;
/*
* The overhead was taken from the original heap memory.
*/
Heap_Block *old_final;
Heap_Block *new_final;
/*
* There are five possibilities for the location of starting
* address:
*
* 1. non-contiguous lower address (NOT SUPPORTED)
* 2. contiguous lower address (NOT SUPPORTED)
* 3. in the heap (ERROR)
* 4. contiguous higher address (SUPPORTED)
* 5. non-contiguous higher address (NOT SUPPORTED)
*
* As noted, this code only supports (4).
*/
if ( starting_address >= (void *) the_heap->start && /* case 3 */
starting_address <= (void *) the_heap->final
)
return HEAP_EXTEND_ERROR;
if ( starting_address < (void *) the_heap->start ) { /* cases 1 and 2 */
return HEAP_EXTEND_NOT_IMPLEMENTED; /* cases 1 and 2 */
} else { /* cases 4 and 5 */
the_block = (Heap_Block *)
_Addresses_Subtract_offset( starting_address, HEAP_OVERHEAD );
if ( the_block != the_heap->final )
return HEAP_EXTEND_NOT_IMPLEMENTED; /* case 5 */
}
/*
* Currently only case 4 should make it to this point.
* The basic trick is to make the extend area look like a used
* block and free it.
*/
*amount_extended = size;
old_final = the_heap->final;
new_final = _Addresses_Add_offset( old_final, size );
/* SAME AS: _Addresses_Add_offset( starting_address, size-HEAP_OVERHEAD ); */
the_heap->final = new_final;
old_final->front_flag =
new_final->back_flag = _Heap_Build_flag( size, HEAP_BLOCK_USED );
new_final->front_flag = HEAP_DUMMY_FLAG;
/*
* Must pass in address of "user" area
* So add in the offset field.
*/
p = (unsigned32 *) &old_final->next;
*p = sizeof(unsigned32);
p++;
_Heap_Free( the_heap, p );
return HEAP_EXTEND_SUCCESSFUL;
}

105
cpukit/score/src/heapfree.c Normal file
View File

@@ -0,0 +1,105 @@
/*
* Heap Handler
*
* COPYRIGHT (c) 1989-1998.
* On-Line Applications Research Corporation (OAR).
* Copyright assigned to U.S. Government, 1994.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <rtems/system.h>
#include <rtems/score/sysstate.h>
#include <rtems/score/heap.h>
/*PAGE
*
* _Heap_Free
*
* This kernel routine returns the memory designated by the
* given heap and given starting address to the memory pool.
*
* Input parameters:
* the_heap - pointer to heap header
* starting_address - starting address of the memory block to free.
*
* Output parameters:
* TRUE - if starting_address is valid heap address
* FALSE - if starting_address is invalid heap address
*/
boolean _Heap_Free(
Heap_Control *the_heap,
void *starting_address
)
{
Heap_Block *the_block;
Heap_Block *next_block;
Heap_Block *new_next_block;
Heap_Block *previous_block;
Heap_Block *temporary_block;
unsigned32 the_size;
the_block = _Heap_User_block_at( starting_address );
if ( !_Heap_Is_block_in( the_heap, the_block ) ||
_Heap_Is_block_free( the_block ) ) {
return( FALSE );
}
the_size = _Heap_Block_size( the_block );
next_block = _Heap_Block_at( the_block, the_size );
if ( !_Heap_Is_block_in( the_heap, next_block ) ||
(the_block->front_flag != next_block->back_flag) ) {
return( FALSE );
}
if ( _Heap_Is_previous_block_free( the_block ) ) {
previous_block = _Heap_Previous_block( the_block );
if ( !_Heap_Is_block_in( the_heap, previous_block ) ) {
return( FALSE );
}
if ( _Heap_Is_block_free( next_block ) ) { /* coalesce both */
previous_block->front_flag += next_block->front_flag + the_size;
temporary_block = _Heap_Next_block( previous_block );
temporary_block->back_flag = previous_block->front_flag;
next_block->next->previous = next_block->previous;
next_block->previous->next = next_block->next;
}
else { /* coalesce prev */
previous_block->front_flag =
next_block->back_flag = previous_block->front_flag + the_size;
}
}
else if ( _Heap_Is_block_free( next_block ) ) { /* coalesce next */
the_block->front_flag = the_size + next_block->front_flag;
new_next_block = _Heap_Next_block( the_block );
new_next_block->back_flag = the_block->front_flag;
the_block->next = next_block->next;
the_block->previous = next_block->previous;
next_block->previous->next = the_block;
next_block->next->previous = the_block;
if (the_heap->first == next_block)
the_heap->first = the_block;
}
else { /* no coalesce */
next_block->back_flag =
the_block->front_flag = the_size;
the_block->previous = _Heap_Head( the_heap );
the_block->next = the_heap->first;
the_heap->first = the_block;
the_block->next->previous = the_block;
}
return( TRUE );
}

View File

@@ -0,0 +1,64 @@
/*
* Heap Handler
*
* COPYRIGHT (c) 1989-1998.
* On-Line Applications Research Corporation (OAR).
* Copyright assigned to U.S. Government, 1994.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <rtems/system.h>
#include <rtems/score/sysstate.h>
#include <rtems/score/heap.h>
/*PAGE
*
* _Heap_Size_of_user_area
*
* This kernel routine returns the size of the memory area
* given heap block.
*
* Input parameters:
* the_heap - pointer to heap header
* starting_address - starting address of the memory block to free.
* size - pointer to size of area
*
* Output parameters:
* size - size of area filled in
* TRUE - if starting_address is valid heap address
* FALSE - if starting_address is invalid heap address
*/
boolean _Heap_Size_of_user_area(
Heap_Control *the_heap,
void *starting_address,
unsigned32 *size
)
{
Heap_Block *the_block;
Heap_Block *next_block;
unsigned32 the_size;
the_block = _Heap_User_block_at( starting_address );
if ( !_Heap_Is_block_in( the_heap, the_block ) ||
_Heap_Is_block_free( the_block ) )
return( FALSE );
the_size = _Heap_Block_size( the_block );
next_block = _Heap_Block_at( the_block, the_size );
if ( !_Heap_Is_block_in( the_heap, next_block ) ||
(the_block->front_flag != next_block->back_flag) )
return( FALSE );
*size = the_size;
return( TRUE );
}

150
cpukit/score/src/heapwalk.c Normal file
View File

@@ -0,0 +1,150 @@
/*
* Heap Handler
*
* COPYRIGHT (c) 1989-1998.
* On-Line Applications Research Corporation (OAR).
* Copyright assigned to U.S. Government, 1994.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <rtems/system.h>
#include <rtems/score/sysstate.h>
#include <rtems/score/heap.h>
/*PAGE
*
* _Heap_Walk
*
* This kernel routine walks the heap and verifies its correctness.
*
* Input parameters:
* the_heap - pointer to heap header
* source - a numeric indicator of the invoker of this routine
* do_dump - when TRUE print the information
*
* Output parameters: NONE
*/
#ifndef RTEMS_DEBUG
void _Heap_Walk(
Heap_Control *the_heap,
int source,
boolean do_dump
)
{
}
#else
#include <stdio.h>
#include <unistd.h>
void _Heap_Walk(
Heap_Control *the_heap,
int source,
boolean do_dump
)
{
Heap_Block *the_block = 0; /* avoid warnings */
Heap_Block *next_block = 0; /* avoid warnings */
int notdone = 1;
int error = 0;
int passes = 0;
/*
* We don't want to allow walking the heap until we have
* transferred control to the user task so we watch the
* system state.
*/
if ( !_System_state_Is_up( _System_state_Get() ) )
return;
the_block = the_heap->start;
if (do_dump == TRUE) {
printf("\nPASS: %d start @ 0x%p final 0x%p, first 0x%p last 0x%p\n",
source, the_heap->start, the_heap->final,
the_heap->first, the_heap->last
);
}
/*
* Handle the 1st block
*/
if (the_block->back_flag != HEAP_DUMMY_FLAG) {
printf("PASS: %d Back flag of 1st block isn't HEAP_DUMMY_FLAG\n", source);
error = 1;
}
while (notdone) {
passes++;
if (error && (passes > 10))
abort();
if (do_dump == TRUE) {
printf("PASS: %d Block @ 0x%p Back %d, Front %d",
source, the_block,
the_block->back_flag, the_block->front_flag);
if ( _Heap_Is_block_free(the_block) ) {
printf( " Prev 0x%p, Next 0x%p\n",
the_block->previous, the_block->next);
} else {
printf("\n");
}
}
/*
* Handle the last block
*/
if ( the_block->front_flag != HEAP_DUMMY_FLAG ) {
next_block = _Heap_Next_block(the_block);
if ( the_block->front_flag != next_block->back_flag ) {
error = 1;
printf("PASS: %d Front and back flags don't match\n", source);
printf(" Current Block (%p): Back - %d, Front - %d",
the_block, the_block->back_flag, the_block->front_flag);
if (do_dump == TRUE) {
if (_Heap_Is_block_free(the_block)) {
printf(" Prev 0x%p, Next 0x%p\n",
the_block->previous, the_block->next);
} else {
printf("\n");
}
} else {
printf("\n");
}
printf(" Next Block (%p): Back - %d, Front - %d",
next_block, next_block->back_flag, next_block->front_flag);
if (do_dump == TRUE) {
if (_Heap_Is_block_free(next_block)) {
printf(" Prev 0x%p, Next 0x%p\n",
the_block->previous, the_block->next);
} else {
printf("\n");
}
} else {
printf("\n");
}
}
}
if (the_block->front_flag == HEAP_DUMMY_FLAG)
notdone = 0;
else
the_block = next_block;
}
if (error)
abort();
}
#endif

View File

@@ -70,916 +70,3 @@ void _Thread_queue_Initialize(
}
}
#if 0
/*PAGE
*
* _Thread_queue_Enqueue
*
* This routine blocks a thread, places it on a thread, and optionally
* starts a timeout timer.
*
* Input parameters:
* the_thread_queue - pointer to threadq
* timeout - interval to wait
*
* Output parameters: NONE
*
* INTERRUPT LATENCY:
* only case
*/
void _Thread_queue_Enqueue(
Thread_queue_Control *the_thread_queue,
Watchdog_Interval timeout
)
{
Thread_Control *the_thread;
the_thread = _Thread_Executing;
#if defined(RTEMS_MULTIPROCESSING)
if ( _Thread_MP_Is_receive( the_thread ) && the_thread->receive_packet )
the_thread = _Thread_MP_Allocate_proxy( the_thread_queue->state );
else
#endif
_Thread_Set_state( the_thread, the_thread_queue->state );
if ( timeout ) {
_Watchdog_Initialize(
&the_thread->Timer,
_Thread_queue_Timeout,
the_thread->Object.id,
NULL
);
_Watchdog_Insert_ticks( &the_thread->Timer, timeout );
}
switch( the_thread_queue->discipline ) {
case THREAD_QUEUE_DISCIPLINE_FIFO:
_Thread_queue_Enqueue_fifo( the_thread_queue, the_thread, timeout );
break;
case THREAD_QUEUE_DISCIPLINE_PRIORITY:
_Thread_queue_Enqueue_priority( the_thread_queue, the_thread, timeout );
break;
}
}
/*PAGE
*
* _Thread_queue_Dequeue
*
* This routine removes a thread from the specified threadq. If the
* threadq discipline is FIFO, it unblocks a thread, and cancels its
* timeout timer. Priority discipline is processed elsewhere.
*
* Input parameters:
* the_thread_queue - pointer to threadq
*
* Output parameters:
* returns - thread dequeued or NULL
*
* INTERRUPT LATENCY:
* check sync
*/
Thread_Control *_Thread_queue_Dequeue(
Thread_queue_Control *the_thread_queue
)
{
Thread_Control *the_thread;
switch ( the_thread_queue->discipline ) {
case THREAD_QUEUE_DISCIPLINE_FIFO:
the_thread = _Thread_queue_Dequeue_fifo( the_thread_queue );
break;
case THREAD_QUEUE_DISCIPLINE_PRIORITY:
the_thread = _Thread_queue_Dequeue_priority( the_thread_queue );
break;
default: /* this is only to prevent warnings */
the_thread = NULL;
break;
}
return( the_thread );
}
/*PAGE
*
* _Thread_queue_Extract_with_proxy
*
* This routine extracts the_thread from the_thread_queue
* and insures that if there is a proxy for this task on
* another node, it is also dealt with.
*
* XXX
*/
boolean _Thread_queue_Extract_with_proxy(
Thread_Control *the_thread
)
{
States_Control state;
Objects_Classes the_class;
Thread_queue_Extract_callout proxy_extract_callout;
state = the_thread->current_state;
if ( _States_Is_waiting_on_thread_queue( state ) ) {
if ( _States_Is_waiting_for_rpc_reply( state ) &&
_States_Is_locally_blocked( state ) ) {
the_class = _Objects_Get_class( the_thread->Wait.id );
proxy_extract_callout = _Thread_queue_Extract_table[ the_class ];
if ( proxy_extract_callout )
(*proxy_extract_callout)( the_thread );
}
_Thread_queue_Extract( the_thread->Wait.queue, the_thread );
return TRUE;
}
return FALSE;
}
/*PAGE
*
* _Thread_queue_Extract
*
* This routine removes a specific thread from the specified threadq,
* deletes any timeout, and unblocks the thread.
*
* Input parameters:
* the_thread_queue - pointer to a threadq header
* the_thread - pointer to a thread control block
*
* Output parameters: NONE
*
* INTERRUPT LATENCY: NONE
*/
void _Thread_queue_Extract(
Thread_queue_Control *the_thread_queue,
Thread_Control *the_thread
)
{
switch ( the_thread_queue->discipline ) {
case THREAD_QUEUE_DISCIPLINE_FIFO:
_Thread_queue_Extract_fifo( the_thread_queue, the_thread );
break;
case THREAD_QUEUE_DISCIPLINE_PRIORITY:
_Thread_queue_Extract_priority( the_thread_queue, the_thread );
break;
}
}
/*PAGE
*
* _Thread_queue_Flush
*
* This kernel routine flushes the given thread queue.
*
* Input parameters:
* the_thread_queue - pointer to threadq to be flushed
* remote_extract_callout - pointer to routine which extracts a remote thread
* status - status to return to the thread
*
* Output parameters: NONE
*/
void _Thread_queue_Flush(
Thread_queue_Control *the_thread_queue,
Thread_queue_Flush_callout remote_extract_callout,
unsigned32 status
)
{
Thread_Control *the_thread;
while ( (the_thread = _Thread_queue_Dequeue( the_thread_queue )) ) {
#if defined(RTEMS_MULTIPROCESSING)
if ( !_Objects_Is_local_id( the_thread->Object.id ) )
( *remote_extract_callout )( the_thread );
else
#endif
the_thread->Wait.return_code = status;
}
}
/*PAGE
*
* _Thread_queue_First
*
* This routines returns a pointer to the first thread on the
* specified threadq.
*
* Input parameters:
* the_thread_queue - pointer to thread queue
*
* Output parameters:
* returns - first thread or NULL
*/
Thread_Control *_Thread_queue_First(
Thread_queue_Control *the_thread_queue
)
{
Thread_Control *the_thread;
switch ( the_thread_queue->discipline ) {
case THREAD_QUEUE_DISCIPLINE_FIFO:
the_thread = _Thread_queue_First_fifo( the_thread_queue );
break;
case THREAD_QUEUE_DISCIPLINE_PRIORITY:
the_thread = _Thread_queue_First_priority( the_thread_queue );
break;
default: /* this is only to prevent warnings */
the_thread = NULL;
break;
}
return the_thread;
}
/*PAGE
*
* _Thread_queue_Timeout
*
* This routine processes a thread which timeouts while waiting on
* a thread queue. It is called by the watchdog handler.
*
* Input parameters:
* id - thread id
*
* Output parameters: NONE
*/
void _Thread_queue_Timeout(
Objects_Id id,
void *ignored
)
{
Thread_Control *the_thread;
Thread_queue_Control *the_thread_queue;
Objects_Locations location;
the_thread = _Thread_Get( id, &location );
switch ( location ) {
case OBJECTS_ERROR:
case OBJECTS_REMOTE: /* impossible */
break;
case OBJECTS_LOCAL:
the_thread_queue = the_thread->Wait.queue;
/*
* If the_thread_queue is not synchronized, then it is either
* "nothing happened", "timeout", or "satisfied". If the_thread
* is the executing thread, then it is in the process of blocking
* and it is the thread which is responsible for the synchronization
* process.
*
* If it is not satisfied, then it is "nothing happened" and
* this is the "timeout" transition. After a request is satisfied,
* a timeout is not allowed to occur.
*/
if ( the_thread_queue->sync_state != THREAD_QUEUE_SYNCHRONIZED &&
_Thread_Is_executing( the_thread ) ) {
if ( the_thread_queue->sync_state != THREAD_QUEUE_SATISFIED )
the_thread_queue->sync_state = THREAD_QUEUE_TIMEOUT;
} else {
the_thread->Wait.return_code = the_thread->Wait.queue->timeout_status;
_Thread_queue_Extract( the_thread->Wait.queue, the_thread );
}
_Thread_Unnest_dispatch();
break;
}
}
/*PAGE
*
* _Thread_queue_Enqueue_fifo
*
* This routine blocks a thread, places it on a thread, and optionally
* starts a timeout timer.
*
* Input parameters:
* the_thread_queue - pointer to threadq
* the_thread - pointer to the thread to block
* timeout - interval to wait
*
* Output parameters: NONE
*
* INTERRUPT LATENCY:
* only case
*/
void _Thread_queue_Enqueue_fifo (
Thread_queue_Control *the_thread_queue,
Thread_Control *the_thread,
Watchdog_Interval timeout
)
{
ISR_Level level;
Thread_queue_States sync_state;
_ISR_Disable( level );
sync_state = the_thread_queue->sync_state;
the_thread_queue->sync_state = THREAD_QUEUE_SYNCHRONIZED;
switch ( sync_state ) {
case THREAD_QUEUE_SYNCHRONIZED:
/*
* This should never happen. It indicates that someone did not
* enter a thread queue critical section.
*/
break;
case THREAD_QUEUE_NOTHING_HAPPENED:
_Chain_Append_unprotected(
&the_thread_queue->Queues.Fifo,
&the_thread->Object.Node
);
_ISR_Enable( level );
return;
case THREAD_QUEUE_TIMEOUT:
the_thread->Wait.return_code = the_thread->Wait.queue->timeout_status;
_ISR_Enable( level );
break;
case THREAD_QUEUE_SATISFIED:
if ( _Watchdog_Is_active( &the_thread->Timer ) ) {
_Watchdog_Deactivate( &the_thread->Timer );
_ISR_Enable( level );
(void) _Watchdog_Remove( &the_thread->Timer );
} else
_ISR_Enable( level );
break;
}
/*
* Global objects with thread queue's should not be operated on from an
* ISR. But the sync code still must allow short timeouts to be processed
* correctly.
*/
_Thread_Unblock( the_thread );
#if defined(RTEMS_MULTIPROCESSING)
if ( !_Objects_Is_local_id( the_thread->Object.id ) )
_Thread_MP_Free_proxy( the_thread );
#endif
}
/*PAGE
*
* _Thread_queue_Dequeue_fifo
*
* This routine removes a thread from the specified threadq.
*
* Input parameters:
* the_thread_queue - pointer to threadq
*
* Output parameters:
* returns - thread dequeued or NULL
*
* INTERRUPT LATENCY:
* check sync
* FIFO
*/
Thread_Control *_Thread_queue_Dequeue_fifo(
Thread_queue_Control *the_thread_queue
)
{
ISR_Level level;
Thread_Control *the_thread;
_ISR_Disable( level );
if ( !_Chain_Is_empty( &the_thread_queue->Queues.Fifo ) ) {
the_thread = (Thread_Control *)
_Chain_Get_first_unprotected( &the_thread_queue->Queues.Fifo );
if ( !_Watchdog_Is_active( &the_thread->Timer ) ) {
_ISR_Enable( level );
_Thread_Unblock( the_thread );
} else {
_Watchdog_Deactivate( &the_thread->Timer );
_ISR_Enable( level );
(void) _Watchdog_Remove( &the_thread->Timer );
_Thread_Unblock( the_thread );
}
#if defined(RTEMS_MULTIPROCESSING)
if ( !_Objects_Is_local_id( the_thread->Object.id ) )
_Thread_MP_Free_proxy( the_thread );
#endif
return the_thread;
}
switch ( the_thread_queue->sync_state ) {
case THREAD_QUEUE_SYNCHRONIZED:
case THREAD_QUEUE_SATISFIED:
_ISR_Enable( level );
return NULL;
case THREAD_QUEUE_NOTHING_HAPPENED:
case THREAD_QUEUE_TIMEOUT:
the_thread_queue->sync_state = THREAD_QUEUE_SATISFIED;
_ISR_Enable( level );
return _Thread_Executing;
}
return NULL; /* this is only to prevent warnings */
}
/*PAGE
*
* _Thread_queue_Extract_fifo
*
* This routine removes a specific thread from the specified threadq,
* deletes any timeout, and unblocks the thread.
*
* Input parameters:
* the_thread_queue - pointer to a threadq header
* the_thread - pointer to the thread to block
*
* Output parameters: NONE
*
* INTERRUPT LATENCY:
* EXTRACT_FIFO
*/
void _Thread_queue_Extract_fifo(
Thread_queue_Control *the_thread_queue,
Thread_Control *the_thread
)
{
ISR_Level level;
_ISR_Disable( level );
if ( !_States_Is_waiting_on_thread_queue( the_thread->current_state ) ) {
_ISR_Enable( level );
return;
}
_Chain_Extract_unprotected( &the_thread->Object.Node );
if ( !_Watchdog_Is_active( &the_thread->Timer ) ) {
_ISR_Enable( level );
} else {
_Watchdog_Deactivate( &the_thread->Timer );
_ISR_Enable( level );
(void) _Watchdog_Remove( &the_thread->Timer );
}
_Thread_Unblock( the_thread );
#if defined(RTEMS_MULTIPROCESSING)
if ( !_Objects_Is_local_id( the_thread->Object.id ) )
_Thread_MP_Free_proxy( the_thread );
#endif
}
/*PAGE
*
* _Thread_queue_First_fifo
*
* This routines returns a pointer to the first thread on the
* specified threadq.
*
* Input parameters:
* the_thread_queue - pointer to threadq
*
* Output parameters:
* returns - first thread or NULL
*/
Thread_Control *_Thread_queue_First_fifo(
Thread_queue_Control *the_thread_queue
)
{
if ( !_Chain_Is_empty( &the_thread_queue->Queues.Fifo ) )
return (Thread_Control *) the_thread_queue->Queues.Fifo.first;
return NULL;
}
/*PAGE
*
* _Thread_queue_Enqueue_priority
*
* This routine blocks a thread, places it on a thread, and optionally
* starts a timeout timer.
*
* Input parameters:
* the_thread_queue - pointer to threadq
* thread - thread to insert
* timeout - timeout interval in ticks
*
* Output parameters: NONE
*
* INTERRUPT LATENCY:
* forward less than
* forward equal
*/
void _Thread_queue_Enqueue_priority(
Thread_queue_Control *the_thread_queue,
Thread_Control *the_thread,
Watchdog_Interval timeout
)
{
Priority_Control search_priority;
Thread_Control *search_thread;
ISR_Level level;
Chain_Control *header;
unsigned32 header_index;
Chain_Node *the_node;
Chain_Node *next_node;
Chain_Node *previous_node;
Chain_Node *search_node;
Priority_Control priority;
States_Control block_state;
Thread_queue_States sync_state;
_Chain_Initialize_empty( &the_thread->Wait.Block2n );
priority = the_thread->current_priority;
header_index = _Thread_queue_Header_number( priority );
header = &the_thread_queue->Queues.Priority[ header_index ];
block_state = the_thread_queue->state;
if ( _Thread_queue_Is_reverse_search( priority ) )
goto restart_reverse_search;
restart_forward_search:
search_priority = PRIORITY_MINIMUM - 1;
_ISR_Disable( level );
search_thread = (Thread_Control *) header->first;
while ( !_Chain_Is_tail( header, (Chain_Node *)search_thread ) ) {
search_priority = search_thread->current_priority;
if ( priority <= search_priority )
break;
#if ( CPU_UNROLL_ENQUEUE_PRIORITY == TRUE )
search_thread = (Thread_Control *) search_thread->Object.Node.next;
if ( _Chain_Is_tail( header, (Chain_Node *)search_thread ) )
break;
search_priority = search_thread->current_priority;
if ( priority <= search_priority )
break;
#endif
_ISR_Flash( level );
if ( !_States_Are_set( search_thread->current_state, block_state) ) {
_ISR_Enable( level );
goto restart_forward_search;
}
search_thread =
(Thread_Control *)search_thread->Object.Node.next;
}
if ( the_thread_queue->sync_state != THREAD_QUEUE_NOTHING_HAPPENED )
goto synchronize;
the_thread_queue->sync_state = THREAD_QUEUE_SYNCHRONIZED;
if ( priority == search_priority )
goto equal_priority;
search_node = (Chain_Node *) search_thread;
previous_node = search_node->previous;
the_node = (Chain_Node *) the_thread;
the_node->next = search_node;
the_node->previous = previous_node;
previous_node->next = the_node;
search_node->previous = the_node;
_ISR_Enable( level );
return;
restart_reverse_search:
search_priority = PRIORITY_MAXIMUM + 1;
_ISR_Disable( level );
search_thread = (Thread_Control *) header->last;
while ( !_Chain_Is_head( header, (Chain_Node *)search_thread ) ) {
search_priority = search_thread->current_priority;
if ( priority >= search_priority )
break;
#if ( CPU_UNROLL_ENQUEUE_PRIORITY == TRUE )
search_thread = (Thread_Control *) search_thread->Object.Node.previous;
if ( _Chain_Is_head( header, (Chain_Node *)search_thread ) )
break;
search_priority = search_thread->current_priority;
if ( priority >= search_priority )
break;
#endif
_ISR_Flash( level );
if ( !_States_Are_set( search_thread->current_state, block_state) ) {
_ISR_Enable( level );
goto restart_reverse_search;
}
search_thread = (Thread_Control *)
search_thread->Object.Node.previous;
}
if ( the_thread_queue->sync_state != THREAD_QUEUE_NOTHING_HAPPENED )
goto synchronize;
the_thread_queue->sync_state = THREAD_QUEUE_SYNCHRONIZED;
if ( priority == search_priority )
goto equal_priority;
search_node = (Chain_Node *) search_thread;
next_node = search_node->next;
the_node = (Chain_Node *) the_thread;
the_node->next = next_node;
the_node->previous = search_node;
search_node->next = the_node;
next_node->previous = the_node;
_ISR_Enable( level );
return;
equal_priority: /* add at end of priority group */
search_node = _Chain_Tail( &search_thread->Wait.Block2n );
previous_node = search_node->previous;
the_node = (Chain_Node *) the_thread;
the_node->next = search_node;
the_node->previous = previous_node;
previous_node->next = the_node;
search_node->previous = the_node;
_ISR_Enable( level );
return;
synchronize:
sync_state = the_thread_queue->sync_state;
the_thread_queue->sync_state = THREAD_QUEUE_SYNCHRONIZED;
switch ( sync_state ) {
case THREAD_QUEUE_SYNCHRONIZED:
/*
* This should never happen. It indicates that someone did not
* enter a thread queue critical section.
*/
break;
case THREAD_QUEUE_NOTHING_HAPPENED:
/*
* This should never happen. All of this was dealt with above.
*/
break;
case THREAD_QUEUE_TIMEOUT:
the_thread->Wait.return_code = the_thread->Wait.queue->timeout_status;
_ISR_Enable( level );
break;
case THREAD_QUEUE_SATISFIED:
if ( _Watchdog_Is_active( &the_thread->Timer ) ) {
_Watchdog_Deactivate( &the_thread->Timer );
_ISR_Enable( level );
(void) _Watchdog_Remove( &the_thread->Timer );
} else
_ISR_Enable( level );
break;
}
/*
* Global objects with thread queue's should not be operated on from an
* ISR. But the sync code still must allow short timeouts to be processed
* correctly.
*/
_Thread_Unblock( the_thread );
#if defined(RTEMS_MULTIPROCESSING)
if ( !_Objects_Is_local_id( the_thread->Object.id ) )
_Thread_MP_Free_proxy( the_thread );
#endif
}
/*PAGE
*
* _Thread_queue_Dequeue_priority
*
* This routine removes a thread from the specified PRIORITY based
* threadq, unblocks it, and cancels its timeout timer.
*
* Input parameters:
* the_thread_queue - pointer to thread queue
*
* Output parameters:
* returns - thread dequeued or NULL
*
* INTERRUPT LATENCY:
* only case
*/
Thread_Control *_Thread_queue_Dequeue_priority(
Thread_queue_Control *the_thread_queue
)
{
unsigned32 index;
ISR_Level level;
Thread_Control *the_thread = NULL; /* just to remove warnings */
Thread_Control *new_first_thread;
Chain_Node *new_first_node;
Chain_Node *new_second_node;
Chain_Node *last_node;
Chain_Node *next_node;
Chain_Node *previous_node;
_ISR_Disable( level );
for( index=0 ;
index < TASK_QUEUE_DATA_NUMBER_OF_PRIORITY_HEADERS ;
index++ ) {
if ( !_Chain_Is_empty( &the_thread_queue->Queues.Priority[ index ] ) ) {
the_thread = (Thread_Control *)
the_thread_queue->Queues.Priority[ index ].first;
goto dequeue;
}
}
switch ( the_thread_queue->sync_state ) {
case THREAD_QUEUE_SYNCHRONIZED:
case THREAD_QUEUE_SATISFIED:
_ISR_Enable( level );
return NULL;
case THREAD_QUEUE_NOTHING_HAPPENED:
case THREAD_QUEUE_TIMEOUT:
the_thread_queue->sync_state = THREAD_QUEUE_SATISFIED;
_ISR_Enable( level );
return _Thread_Executing;
}
dequeue:
new_first_node = the_thread->Wait.Block2n.first;
new_first_thread = (Thread_Control *) new_first_node;
next_node = the_thread->Object.Node.next;
previous_node = the_thread->Object.Node.previous;
if ( !_Chain_Is_empty( &the_thread->Wait.Block2n ) ) {
last_node = the_thread->Wait.Block2n.last;
new_second_node = new_first_node->next;
previous_node->next = new_first_node;
next_node->previous = new_first_node;
new_first_node->next = next_node;
new_first_node->previous = previous_node;
if ( !_Chain_Has_only_one_node( &the_thread->Wait.Block2n ) ) {
/* > two threads on 2-n */
new_second_node->previous =
_Chain_Head( &new_first_thread->Wait.Block2n );
new_first_thread->Wait.Block2n.first = new_second_node;
new_first_thread->Wait.Block2n.last = last_node;
last_node->next = _Chain_Tail( &new_first_thread->Wait.Block2n );
}
} else {
previous_node->next = next_node;
next_node->previous = previous_node;
}
if ( !_Watchdog_Is_active( &the_thread->Timer ) ) {
_ISR_Enable( level );
_Thread_Unblock( the_thread );
} else {
_Watchdog_Deactivate( &the_thread->Timer );
_ISR_Enable( level );
(void) _Watchdog_Remove( &the_thread->Timer );
_Thread_Unblock( the_thread );
}
#if defined(RTEMS_MULTIPROCESSING)
if ( !_Objects_Is_local_id( the_thread->Object.id ) )
_Thread_MP_Free_proxy( the_thread );
#endif
return( the_thread );
}
/*PAGE
*
* _Thread_queue_Extract_priority
*
* This routine removes a specific thread from the specified threadq,
* deletes any timeout, and unblocks the thread.
*
* Input parameters:
* the_thread_queue - pointer to a threadq header
* the_thread - pointer to a thread control block
*
* Output parameters: NONE
*
* INTERRUPT LATENCY:
* EXTRACT_PRIORITY
*/
void _Thread_queue_Extract_priority(
Thread_queue_Control *the_thread_queue,
Thread_Control *the_thread
)
{
ISR_Level level;
Chain_Node *the_node;
Chain_Node *next_node;
Chain_Node *previous_node;
Thread_Control *new_first_thread;
Chain_Node *new_first_node;
Chain_Node *new_second_node;
Chain_Node *last_node;
the_node = (Chain_Node *) the_thread;
_ISR_Disable( level );
if ( _States_Is_waiting_on_thread_queue( the_thread->current_state ) ) {
next_node = the_node->next;
previous_node = the_node->previous;
if ( !_Chain_Is_empty( &the_thread->Wait.Block2n ) ) {
new_first_node = the_thread->Wait.Block2n.first;
new_first_thread = (Thread_Control *) new_first_node;
last_node = the_thread->Wait.Block2n.last;
new_second_node = new_first_node->next;
previous_node->next = new_first_node;
next_node->previous = new_first_node;
new_first_node->next = next_node;
new_first_node->previous = previous_node;
if ( !_Chain_Has_only_one_node( &the_thread->Wait.Block2n ) ) {
/* > two threads on 2-n */
new_second_node->previous =
_Chain_Head( &new_first_thread->Wait.Block2n );
new_first_thread->Wait.Block2n.first = new_second_node;
new_first_thread->Wait.Block2n.last = last_node;
last_node->next = _Chain_Tail( &new_first_thread->Wait.Block2n );
}
} else {
previous_node->next = next_node;
next_node->previous = previous_node;
}
if ( !_Watchdog_Is_active( &the_thread->Timer ) ) {
_ISR_Enable( level );
_Thread_Unblock( the_thread );
} else {
_Watchdog_Deactivate( &the_thread->Timer );
_ISR_Enable( level );
(void) _Watchdog_Remove( &the_thread->Timer );
_Thread_Unblock( the_thread );
}
#if defined(RTEMS_MULTIPROCESSING)
if ( !_Objects_Is_local_id( the_thread->Object.id ) )
_Thread_MP_Free_proxy( the_thread );
#endif
}
else
_ISR_Enable( level );
}
/*PAGE
*
* _Thread_queue_First_priority
*
* This routines returns a pointer to the first thread on the
* specified threadq.
*
* Input parameters:
* the_thread_queue - pointer to thread queue
*
* Output parameters:
* returns - first thread or NULL
*/
Thread_Control *_Thread_queue_First_priority (
Thread_queue_Control *the_thread_queue
)
{
unsigned32 index;
for( index=0 ;
index < TASK_QUEUE_DATA_NUMBER_OF_PRIORITY_HEADERS ;
index++ ) {
if ( !_Chain_Is_empty( &the_thread_queue->Queues.Priority[ index ] ) )
return (Thread_Control *)
the_thread_queue->Queues.Priority[ index ].first;
}
return NULL;
}
#endif