diff options
Diffstat (limited to 'cpukit/score/src')
203 files changed, 16199 insertions, 0 deletions
diff --git a/cpukit/score/src/Unlimited.txt b/cpukit/score/src/Unlimited.txt new file mode 100644 index 0000000000..47309c361c --- /dev/null +++ b/cpukit/score/src/Unlimited.txt @@ -0,0 +1,364 @@ +# +# $Id$ +# + +This document explains how the unlimited objects support works. This was +written by Chris Johns <ccj@acm.org> of Objective Design Systems as a +design document. This was submitted as part of the patch which added +this capability. + +Unlimited Local Node Objects +============================ + +1. Why ? + +This patch changes the way RTEMS allocates, frees, and manages the +'Objects_Control' structure. + +The 'Objects_Control' structure is at the root of all objects in +RTEMS. The RTEMS and POSIX API allows users to create tasks, message +queues, semaphores and other resources. These are all a type of +Object. The POSIX API allow similar operations. These also map to +Objects. + +Currently the number of objects that can be created is a static value +loaded into the Configuration table before starting the kernel. The +application cannot exceed these limits. Various means are used to tune +this value. During development the value is usually set large. This +saves having to change it everytime a developer adds a new +resource. With a large team of developers the configuration table file +can cycle through a large number of revisions. The wasted memory is +only recovered when memory runs short. The issue of the configuration +table parameters become more important the less memory you have. + +The Configuration table requires a calculation to occur at compile +time to set the size of the Workspace. The calculation is an +estimate. You need to specify an overhead value for memory that can +not be calculated. An example of memory that cannot be calculated is +stack sizes. This issue is not directly related to allowing unlimited +objects how-ever the need to calculate the memory usage for a system +in this manner is prone to error. + +I would like to see download support added to RTEMS. The kernel +configuration being set at boot time means a download application can +be limited. This can defeat one of the purposes of using downloaded +code, no need to change ROMs. In a system I worked on the cost to +change ROMS in a complete system was high and could take a week. This +change is the first phase of supporting downloaded applications. + +1.1 How do Objects work ? + +All applications interact with the super core (c/src/exec/score) via +an API. The central structure used in the super core is the +`object'. Two application interfaces exist. They are RTEMS and +POSIX. Both map to the super core using objects. + +An object in RTEMS is a resource which the user (through the API) +creates. The different types of objects are referred to as classes of +objects. An object is referenced by an id. This is of type `rtems_id' +and is a 32bit unsigned integer. The id is unique for each object no +matter what class. + +Objects are anchored by the `_Object_Information' structure. There is +one per type or class of object. A global table of pointers to each +information structure for a class of objects is held in +`Objects_Information_table'. + +Objects consist of 6 main structures. The `_Object_Information' is the +root structure. It contains pointers to the `local_table', +`name_table', `global_table', the Inactive chain, and the object +memory. It also contains the various variables which describe the +object. We are only concerned with the `local_table', `name_table', +Inactive chain, and the object memory to support unlimited objects. + +The `local_table' holds the pointers to open objects. A `local_table +entry which is null is free and the object will be sitting on the +Inactive chain. The index into the table is based on part of the +id. Given an id the you can find the index into the `local_table', and +therefore the object. The `local_table' has the entries for the +indexes below the minimum_id's index. The minimum_id is always set to +1 (the change allows another value to be selected if require). The +index of 0 is reserved and never used. This allows any actions using +an id of zero to fail or map to a special case. + +The `name_table' holds the names of the objects. Each entry in this +table is the maximum size the name of the object can be. The size of +names is not constrained by the object code (but is by the MP object +code, and the API and should be fixed). + +The `global_table' and code that uses it has not changed. I did not +look at the this code, and I am not farmilar with it. + +The Inactive chain stores objects which are free or not +allocated. This design saves searching for a free object when +allocating therefore providing a deterministic allocation scheme. When +the chain is empty a null is returned. + +The change documented below basically extends the `local_table' and +`name_table' structures at run-time. The memory used be these table +is not large compared to the memory for the objects, and so are never +reduced in size once extended. The object's memory grows and shrinks +depending of the user's usage. + +Currently, the user specifies the total number of objects in the +Configuration table. The change alters the function of the values in +the Configuration table. A flag can be masked on to the value which +selects the extending mode. If the user does not set the flag the +object code operates with an object ceiling. A small performance +overhead will be incurred as the allocate and free routines are now +not inlined and a check of the auto_extend flag is made. The remaining +value field of the Configuration table entry is total number of +objects that can be allocated when not in unlimited mode. + +If the user masks the flag on to a value on the Configuration table +auto-exdending mode is selected for that class of object. The value +becomes the allocation unit size. If there are no free objects the +object's tables are extended by the allocation unit number of +objects. The object table is shrunk when the user frees objects. The +table must have one free allocation block, and at least half the +allocation size of another block before the object memory of the free +allocation block is returned to the heap. This stops threshold +thrashing when objects around the allocation unit size and created and +destroyed. + +At least one allocation block size of objects is created and never +destroyed. + +The change to support unlimited objects has extended the object +information structure. + +The flag, `auto_extend' controls if the object can be automatically +extended. The user masks the flag RTEMS_UNLIMITED_FLAGS onto the +Configuration table number to select the auto-extend mode. This is +passed to the `_Objects_Initialize_information' function in the +parameter maximum. The flag is tested for and the auto_extend flag +updated to reflect the state of the flag before being stipped from the +maximum. + +The `allocation_size' is set to the parameter maxium in the function +`_Objects_Initialize_information' if `auto_extend' is true. Making the +allocation size small causes the memory to be allocated and freed more +often. This only effects the performance times for creating a resource +such as a task. It does how-ever give you fine grain memory +control. If the performance of creating resources is not a problem +make the size small. + +The size of the object is required to be stored. It is used when +extending the object information. + +A count of the object on the Inactive list is maintained. This is used +during freeing objects. If the count is above 1.5 times the +`allocation_size' an attempt is made to shrink the object +informtation. Shrinking might not always succeed as a single +allocation block might not be free. Random freeing of objects can +result in some fragmentation. Any further allocations will use the +free objects before extending the object's information tables. + +A table of inactive objects per block is maintained. This table, like +the `local_table' and `name_table' grows as more blocks are +allocated. A check is made of a blocks inactive count when an object +which is part of that block is freed. If the total inactive count +exceeds 1.5 times the allocation size, and the block's inactive count +is the allocation_size, the objects data block is returnd to the +workspace heap. + +The `objects_blocks' is a table of pointers. The object_block's pointers +point to the object's data block. The object's data block is a single +allocation of the name space and object space. This was two separate +allocations but is now one. The objects_block's table is use to +determine if a block is allocated, and the address of the memory block +to be returned to the workspace heap when the object informtation +space is shrunk. + +2.0 Detail Of the Auto-Extend Patch to rtems-4.0.0, Snapshot 19990302 + +o Configuration table support. + + Added a flag OBJECTS_UNLIMITED_OBJECTS to score/headers/object.h + header file. This is referenced in the file sapi/headers/config.h to + create the flag RTEMS_UNLIMITED_OBJECTS. A macro is provided to take + a resource count and apply the flag. The macro is called + `rtems_resource_unlimited'. The user uses this macro when building a + configuration table. It can be used with the condefs.h header file. + +o Object Information Structure + + The object information structure, Objects_Information, has been + extended with the follow fields : + + boolean auto_extend - + + When true the object's information tables can be extended untill + all memory is used. When false the current functionallity is + maintained. + + uint32_t allocation_size - + + When auto_extend is true, it is the value in the Configuration + table and is the number of objects the object's information + tables are extended or shrunk. + + uint32_t size - + + The size of the object. It is used to calculate the size of + memory required to be allocated when extending the table. + + uint32_t inactive - + + The number of elements on the Inactive chain. + + uint32_t *inactive_per_block - + + Pointer to a table of counts of the inactive objects from a + block on the Inactive chain. It is used to know which blocks are + all free and therefore can be returned to the heap. + + void **object_blocks - + + Pointer to a table of pointers to the object data. The table + holds the pointer used to return a block to the heap when + shrinking the object's information tables. + +o Changes to Existing Object Functions + + Two functions prototypes are added. They are : + + _Objects_Extend_information, + _Objects_Shrink_information + _Object_Allocate, and + _Object_Free + + The last were inlined, how-ever now they are not as they are too + complex to implement as macros now. + +o Object Initialisation + + The function _Objects_Initialize_information has been changed to + initialisation of the information structure's fields then call the + new function _Objects_Extend_information. + + The first block of objects is always allocated and never + released. This means with the auto-extend flag set to true the user + still sees the same behaviour expected without this change. That is + the number objects specified in the Configuration table is the + number of object allocated during RTEMS initialisation. If not + enough memory is found during this initial extend a fatal error + occurs. The fatal error only occurs for this case of extending the + object's information tables. + +o Object Information Extend + + The _Object_Information_Extend is a new function. It takes some of + the code form the old _Object_Initialize_information function. The + function extends an object's information base. + + Extending the first time is a special case. The function assumes the + maximum index will be less than the minimum index. This means the + minimum index must be greater than 0 at initialisation. The other + special case made is coping the tables from the old location to the + new location. The first block case is trapped and tables are + initialised instead. Workspace allocation for the first block is + tested for an if the first block the allocate or fatal error call is + made. This traps an RTEMS initialise allocation error. + + The remainder of the code deals with all cases of extending the + object's information. + + The current block count is first determined, then a scan of the + object_block table is made to locate a free slot. Blocks can be + freed in any order. The index base for the block is also determined. + + If the index base is greater than the maximum index, the tables must + grow. To grow the tables, a new larger memory block is allocated and + the tables copied. The object's information structure is then + updated to point to the new tables. The tables are allocated in one + memory block from the work-space heap. The single block is then + broken down in the required tables. + + Once the tables are copied, and the new extended parts initialised + the table pointers in the object's information structure are + updated. This is protected by masking interrupts. + + The old table's memory block is returned to the heap. + + The names table and object is allocated. This again is a single + block which is divided. + + The objects are initialised onto a local Inactive chain. They are + then copied to the object's Inactive chain to complete the + initialisation. + +o Object Informtation Shrink + + The _Object_Shrink_information function is new. It is required to + scan all the blocks to see which one has no objects allocated. The + last object freed might not belong to a block which is completely + free. + + Once a block is located, the Inactive chain is interated down + looking for objects which belong to the block of object being + released. + + Once the Inactive chain scan is complete the names table and object + memory is returned to the work-space heap and the table references cleared. + + XXX - I am not sure if this should occur if better protection or + different code to provide better protection. + + The information tables do not change size. Once extended they never + shrink. + +o Object Allocation + + The _Objects_Allocate attempts to get an object from the Inactive + chain. If auto-extend mode is not enabled no further processing + occurs. The extra overhead for this implemetation is the function is + not inlined and check of a boolean occurs. It should effect the + timing figures. + + If auto-extend is enabled, a further check is made to see if the get + from the Inactive chain suceeded in getting an object. If it failed + a call is made to extend the object's information tables. + + The get from the Inactive chain is retried. The result of this is + returned to the user. A failure here is the users problem. + +o Object Free + + The _Objects_Free puts the object back onto the Inactive + chain. Again if auto-extend mode is not enabled no further + processing occurs and performance overhead will low. + + If auto-extend mode is enabled, a check is to see if the number of + Inactive objects is one and a half times the allocation size. If + there are that many free objects an attempt is made to shrink the + object's information. + +o Object Index and the Get Function + + The existing code allocates the number of object specified in the + configuration table, how-ever it makes the local_table have one more + element. This is the slot for an id of 0. The 0 slot is always a + NULL providing a simple check for a 0 id for object classes. + + The existing _Objects_Get code removes the minimum id, which I think + could only be 1 from the index, then adds one for the 0 slot. + + This change removes this index adjustment code in _Objects_Get. + + The extend information starts the index count when scanning for free + blocks at the minumun index. This means the base index for a block + will always be adjusted by the minimum index. The extend information + function only ever allocates the allocation size of + objects. Finially the object's local_table size is the maximum plus + the minumum index size. The maximum is really the maximum index. + + This means the values in the object's information structure and + tables do not need the index adjustments which existed before. + +o The Test + + A new sample test, unlimited is provided. It attempts to test this + change. + + diff --git a/cpukit/score/src/apiext.c b/cpukit/score/src/apiext.c new file mode 100644 index 0000000000..a08977113e --- /dev/null +++ b/cpukit/score/src/apiext.c @@ -0,0 +1,113 @@ +/* apiext.c + * + * XXX + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/apiext.h> + +/*PAGE + * + * _API_extensions_Initialization + */ + +void _API_extensions_Initialization( void ) +{ + _Chain_Initialize_empty( &_API_extensions_List ); +} + +/*PAGE + * + * _API_extensions_Add + */ + +void _API_extensions_Add( + API_extensions_Control *the_extension +) +{ + _Chain_Append( &_API_extensions_List, &the_extension->Node ); +} + +#if defined(FUNCTIONALITY_NOT_CURRENTLY_USED_BY_ANY_API) + /*PAGE + * + * _API_extensions_Run_predriver + */ + + void _API_extensions_Run_predriver( void ) + { + Chain_Node *the_node; + API_extensions_Control *the_extension; + + for ( the_node = _Chain_First( &_API_extensions_List ); + !_Chain_Is_tail( &_API_extensions_List, the_node ) ; + the_node = the_node->next ) { + + the_extension = (API_extensions_Control *) the_node; + + if ( the_extension->predriver_hook ) + (*the_extension->predriver_hook)(); + } + } +#endif + +/*PAGE + * + * _API_extensions_Run_postdriver + */ + +void _API_extensions_Run_postdriver( void ) +{ + Chain_Node *the_node; + API_extensions_Control *the_extension; + + for ( the_node = _Chain_First( &_API_extensions_List ); + !_Chain_Is_tail( &_API_extensions_List, the_node ) ; + the_node = the_node->next ) { + + the_extension = (API_extensions_Control *) the_node; + + /* + * Currently all APIs configure this hook so it is always non-NULL. + */ +#if defined(FUNCTIONALITY_NOT_CURRENTLY_USED_BY_ANY_API) + if ( the_extension->postdriver_hook ) +#endif + (*the_extension->postdriver_hook)(); + } +} + +/*PAGE + * + * _API_extensions_Run_postswitch + */ + +void _API_extensions_Run_postswitch( void ) +{ + Chain_Node *the_node; + API_extensions_Control *the_extension; + + for ( the_node = _Chain_First( &_API_extensions_List ); + !_Chain_Is_tail( &_API_extensions_List, the_node ) ; + the_node = the_node->next ) { + + the_extension = (API_extensions_Control *) the_node; + + (*the_extension->postswitch_hook)( _Thread_Executing ); + } +} + +/* end of file */ diff --git a/cpukit/score/src/apimutex.c b/cpukit/score/src/apimutex.c new file mode 100644 index 0000000000..93e67eafaf --- /dev/null +++ b/cpukit/score/src/apimutex.c @@ -0,0 +1,37 @@ +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/apimutex.h> + +void _API_Mutex_Initialization( + uint32_t maximum_mutexes +) +{ + _Objects_Initialize_information( + &_API_Mutex_Information, /* object information table */ + OBJECTS_INTERNAL_API, /* object API */ + OBJECTS_INTERNAL_MUTEXES, /* object class */ + maximum_mutexes, /* maximum objects of this class */ + sizeof( API_Mutex_Control ), /* size of this object's control block */ + false, /* true if the name is a string */ + 0 /* maximum length of an object name */ +#if defined(RTEMS_MULTIPROCESSING) + , + true, /* true if this is a global object class */ + NULL /* Proxy extraction support callout */ +#endif + ); +} diff --git a/cpukit/score/src/apimutexallocate.c b/cpukit/score/src/apimutexallocate.c new file mode 100644 index 0000000000..5a2a323315 --- /dev/null +++ b/cpukit/score/src/apimutexallocate.c @@ -0,0 +1,39 @@ +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/apimutex.h> + +void _API_Mutex_Allocate( + API_Mutex_Control **the_mutex +) +{ + API_Mutex_Control *mutex; + + CORE_mutex_Attributes attr = { + CORE_MUTEX_NESTING_ACQUIRES, + false, + CORE_MUTEX_DISCIPLINES_PRIORITY_INHERIT, + 0 + }; + + mutex = (API_Mutex_Control *) _Objects_Allocate( &_API_Mutex_Information ); + + _CORE_mutex_Initialize( &mutex->Mutex, &attr, CORE_MUTEX_UNLOCKED ); + + _Objects_Open_u32( &_API_Mutex_Information, &mutex->Object, 1 ); + + *the_mutex = mutex; +} diff --git a/cpukit/score/src/apimutexlock.c b/cpukit/score/src/apimutexlock.c new file mode 100644 index 0000000000..6729478ae4 --- /dev/null +++ b/cpukit/score/src/apimutexlock.c @@ -0,0 +1,34 @@ +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/apimutex.h> + +void _API_Mutex_Lock( + API_Mutex_Control *the_mutex +) +{ + ISR_Level level; + + _ISR_Disable( level ); + + _CORE_mutex_Seize( + &the_mutex->Mutex, + the_mutex->Object.id, + true, + 0, + level + ); +} diff --git a/cpukit/score/src/apimutexunlock.c b/cpukit/score/src/apimutexunlock.c new file mode 100644 index 0000000000..ca824a6e6c --- /dev/null +++ b/cpukit/score/src/apimutexunlock.c @@ -0,0 +1,30 @@ +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/apimutex.h> + +void _API_Mutex_Unlock( + API_Mutex_Control *the_mutex +) +{ + _Thread_Disable_dispatch(); + _CORE_mutex_Surrender( + &the_mutex->Mutex, + the_mutex->Object.id, + NULL + ); + _Thread_Enable_dispatch(); +} diff --git a/cpukit/score/src/chain.c b/cpukit/score/src/chain.c new file mode 100644 index 0000000000..85821d4d71 --- /dev/null +++ b/cpukit/score/src/chain.c @@ -0,0 +1,61 @@ +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/address.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> + +/*PAGE + * + * _Chain_Initialize + * + * This kernel routine initializes a doubly linked chain. + * + * Input parameters: + * the_chain - pointer to chain header + * starting_address - starting address of first node + * number_nodes - number of nodes in chain + * node_size - size of node in bytes + * + * Output parameters: NONE + */ + +void _Chain_Initialize( + Chain_Control *the_chain, + void *starting_address, + size_t number_nodes, + size_t node_size +) +{ + size_t count = number_nodes; + Chain_Node *head = _Chain_Head( the_chain ); + Chain_Node *tail = _Chain_Tail( the_chain ); + Chain_Node *current = head; + Chain_Node *next = starting_address; + + head->previous = NULL; + + while ( count-- ) { + current->next = next; + next->previous = current; + current = next; + next = (Chain_Node *) + _Addresses_Add_offset( (void *) next, node_size ); + } + + current->next = tail; + tail->previous = current; +} diff --git a/cpukit/score/src/chainappend.c b/cpukit/score/src/chainappend.c new file mode 100644 index 0000000000..f5287a450f --- /dev/null +++ b/cpukit/score/src/chainappend.c @@ -0,0 +1,46 @@ +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/address.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> + +/* + * _Chain_Append + * + * This kernel routine puts a node on the end of the specified chain. + * + * Input parameters: + * the_chain - pointer to chain header + * node - address of node to put at rear of chain + * + * Output parameters: NONE + * + * INTERRUPT LATENCY: + * only case + */ + +void _Chain_Append( + Chain_Control *the_chain, + Chain_Node *node +) +{ + ISR_Level level; + + _ISR_Disable( level ); + _Chain_Append_unprotected( the_chain, node ); + _ISR_Enable( level ); +} diff --git a/cpukit/score/src/chainappendempty.c b/cpukit/score/src/chainappendempty.c new file mode 100644 index 0000000000..33033df8ed --- /dev/null +++ b/cpukit/score/src/chainappendempty.c @@ -0,0 +1,44 @@ +/** + * @file + * + * @ingroup ScoreChain + * + * @brief _Chain_Append_with_empty_check() implementation. + */ + +/* + * Copyright (c) 2010 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> + +bool _Chain_Append_with_empty_check( + Chain_Control *chain, + Chain_Node *node +) +{ + ISR_Level level; + bool was_empty; + + _ISR_Disable( level ); + was_empty = _Chain_Append_with_empty_check_unprotected( chain, node ); + _ISR_Enable( level ); + + return was_empty; +} diff --git a/cpukit/score/src/chainextract.c b/cpukit/score/src/chainextract.c new file mode 100644 index 0000000000..deb537ed85 --- /dev/null +++ b/cpukit/score/src/chainextract.c @@ -0,0 +1,44 @@ +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/address.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> + +/* + * _Chain_Extract + * + * This kernel routine deletes the given node from a chain. + * + * Input parameters: + * node - pointer to node in chain to be deleted + * + * Output parameters: NONE + * + * INTERRUPT LATENCY: + * only case + */ + +void _Chain_Extract( + Chain_Node *node +) +{ + ISR_Level level; + + _ISR_Disable( level ); + _Chain_Extract_unprotected( node ); + _ISR_Enable( level ); +} diff --git a/cpukit/score/src/chainget.c b/cpukit/score/src/chainget.c new file mode 100644 index 0000000000..4ec11c112e --- /dev/null +++ b/cpukit/score/src/chainget.c @@ -0,0 +1,51 @@ +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/address.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> + +/* + * _Chain_Get + * + * This kernel routine returns a pointer to a node taken from the + * given chain. + * + * Input parameters: + * the_chain - pointer to chain header + * + * Output parameters: + * return_node - pointer to node in chain allocated + * CHAIN_END - if no nodes available + * + * INTERRUPT LATENCY: + * only case + */ + +Chain_Node *_Chain_Get( + Chain_Control *the_chain +) +{ + ISR_Level level; + Chain_Node *return_node; + + return_node = NULL; + _ISR_Disable( level ); + if ( !_Chain_Is_empty( the_chain ) ) + return_node = _Chain_Get_first_unprotected( the_chain ); + _ISR_Enable( level ); + return return_node; +} diff --git a/cpukit/score/src/chaingetempty.c b/cpukit/score/src/chaingetempty.c new file mode 100644 index 0000000000..3f9be4de5b --- /dev/null +++ b/cpukit/score/src/chaingetempty.c @@ -0,0 +1,44 @@ +/** + * @file + * + * @ingroup ScoreChain + * + * @brief _Chain_Get_with_empty_check() implementation. + */ + +/* + * Copyright (c) 2010 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> + +bool _Chain_Get_with_empty_check( + Chain_Control *chain, + Chain_Node **node +) +{ + ISR_Level level; + bool is_empty_now; + + _ISR_Disable( level ); + is_empty_now = _Chain_Get_with_empty_check_unprotected( chain, node ); + _ISR_Enable( level ); + + return is_empty_now; +} diff --git a/cpukit/score/src/chaininsert.c b/cpukit/score/src/chaininsert.c new file mode 100644 index 0000000000..0f5cdd25ab --- /dev/null +++ b/cpukit/score/src/chaininsert.c @@ -0,0 +1,47 @@ +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/address.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> + +/* + * _Chain_Insert + * + * This kernel routine inserts a given node after a specified node + * a requested chain. + * + * Input parameters: + * after_node - pointer to node in chain to be inserted after + * node - pointer to node to be inserted + * + * Output parameters: NONE + * + * INTERRUPT LATENCY: + * only case + */ + +void _Chain_Insert( + Chain_Node *after_node, + Chain_Node *node +) +{ + ISR_Level level; + + _ISR_Disable( level ); + _Chain_Insert_unprotected( after_node, node ); + _ISR_Enable( level ); +} diff --git a/cpukit/score/src/chainprependempty.c b/cpukit/score/src/chainprependempty.c new file mode 100644 index 0000000000..9dfd9a653f --- /dev/null +++ b/cpukit/score/src/chainprependempty.c @@ -0,0 +1,44 @@ +/** + * @file + * + * @ingroup ScoreChain + * + * @brief _Chain_Prepend_with_empty_check() implementation. + */ + +/* + * Copyright (c) 2010 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> + +bool _Chain_Prepend_with_empty_check( + Chain_Control *chain, + Chain_Node *node +) +{ + ISR_Level level; + bool was_empty; + + _ISR_Disable( level ); + was_empty = _Chain_Prepend_with_empty_check_unprotected( chain, node ); + _ISR_Enable( level ); + + return was_empty; +} diff --git a/cpukit/score/src/corebarrier.c b/cpukit/score/src/corebarrier.c new file mode 100644 index 0000000000..55f093ccc3 --- /dev/null +++ b/cpukit/score/src/corebarrier.c @@ -0,0 +1,57 @@ +/* + * SuperCore Barrier Handler + * + * DESCRIPTION: + * + * This package is part of the implementation of the SuperCore Barrier Handler. + * + * COPYRIGHT (c) 1989-2006. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/corebarrier.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> + +/*PAGE + * + * _CORE_barrier_Initialize + * + * This function initialize a barrier and sets the initial value based + * on the given count. + * + * Input parameters: + * the_barrier - the barrier control block to initialize + * the_barrier_attributes - the attributes specified at create time + * + * Output parameters: NONE + */ + +void _CORE_barrier_Initialize( + CORE_barrier_Control *the_barrier, + CORE_barrier_Attributes *the_barrier_attributes +) +{ + + the_barrier->Attributes = *the_barrier_attributes; + the_barrier->number_of_waiting_threads = 0; + + _Thread_queue_Initialize( + &the_barrier->Wait_queue, + THREAD_QUEUE_DISCIPLINE_FIFO, + STATES_WAITING_FOR_BARRIER, + CORE_BARRIER_TIMEOUT + ); +} diff --git a/cpukit/score/src/corebarrierrelease.c b/cpukit/score/src/corebarrierrelease.c new file mode 100644 index 0000000000..7bf341d4c7 --- /dev/null +++ b/cpukit/score/src/corebarrierrelease.c @@ -0,0 +1,70 @@ +/* + * SuperCore Barrier Handler + * + * DESCRIPTION: + * + * This package is part of the implementation of the SuperCore Barrier Handler. + * + * COPYRIGHT (c) 1989-2006. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/corebarrier.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> + +/*PAGE + * + * _CORE_barrier_Release + * + * Input parameters: + * the_barrier - the barrier to be flushed + * id - id of the object for a remote unblock + * api_barrier_mp_support - api dependent MP support actions + * + * Output parameters: + * CORE_BARRIER_STATUS_SUCCESSFUL - if successful + * core error code - if unsuccessful + * + * Output parameters: + * returns number of threads unblocked + */ + +uint32_t _CORE_barrier_Release( + CORE_barrier_Control *the_barrier, +#if defined(RTEMS_MULTIPROCESSING) + Objects_Id id, + CORE_barrier_API_mp_support_callout api_barrier_mp_support +#else + Objects_Id id __attribute__((unused)), + CORE_barrier_API_mp_support_callout api_barrier_mp_support __attribute__((unused)) +#endif +) +{ + Thread_Control *the_thread; + uint32_t count; + + count = 0; + while ( (the_thread = _Thread_queue_Dequeue(&the_barrier->Wait_queue)) ) { +#if defined(RTEMS_MULTIPROCESSING) + if ( !_Objects_Is_local_id( the_thread->Object.id ) ) + (*api_barrier_mp_support) ( the_thread, id ); +#endif + count++; + } + the_barrier->number_of_waiting_threads = 0; + return count; +} diff --git a/cpukit/score/src/corebarrierwait.c b/cpukit/score/src/corebarrierwait.c new file mode 100644 index 0000000000..4db276f1ce --- /dev/null +++ b/cpukit/score/src/corebarrierwait.c @@ -0,0 +1,78 @@ +/* + * SuperCore Barrier Handler + * + * DESCRIPTION: + * + * This package is part of the implementation of the SuperCore Barrier Handler. + * + * COPYRIGHT (c) 1989-2006. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/corebarrier.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> + +/*PAGE + * + * _CORE_barrier_Wait + * + * Input parameters: + * the_barrier - pointer to barrier control block + * id - id of object to wait on + * wait - true if wait is allowed, false otherwise + * timeout - number of ticks to wait (0 means forever) + * api_barrier_mp_support - api dependent MP support actions + * + * Output parameters: NONE + * + * INTERRUPT LATENCY: + * available + * wait + */ + +void _CORE_barrier_Wait( + CORE_barrier_Control *the_barrier, + Objects_Id id, + bool wait, + Watchdog_Interval timeout, + CORE_barrier_API_mp_support_callout api_barrier_mp_support +) +{ + Thread_Control *executing; + ISR_Level level; + + executing = _Thread_Executing; + executing->Wait.return_code = CORE_BARRIER_STATUS_SUCCESSFUL; + _ISR_Disable( level ); + the_barrier->number_of_waiting_threads++; + if ( _CORE_barrier_Is_automatic( &the_barrier->Attributes ) ) { + if ( the_barrier->number_of_waiting_threads == + the_barrier->Attributes.maximum_count) { + executing->Wait.return_code = CORE_BARRIER_STATUS_AUTOMATICALLY_RELEASED; + _ISR_Enable( level ); + _CORE_barrier_Release( the_barrier, id, api_barrier_mp_support ); + return; + } + } + + _Thread_queue_Enter_critical_section( &the_barrier->Wait_queue ); + executing->Wait.queue = &the_barrier->Wait_queue; + executing->Wait.id = id; + _ISR_Enable( level ); + + _Thread_queue_Enqueue( &the_barrier->Wait_queue, timeout ); +} diff --git a/cpukit/score/src/coremsg.c b/cpukit/score/src/coremsg.c new file mode 100644 index 0000000000..4e3b9545e1 --- /dev/null +++ b/cpukit/score/src/coremsg.c @@ -0,0 +1,120 @@ +/* + * CORE Message Queue Handler + * + * DESCRIPTION: + * + * This package is the implementation of the CORE Message Queue Handler. + * This core object provides task synchronization and communication functions + * via messages passed to queue objects. + * + * COPYRIGHT (c) 1989-2009. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/coremsg.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> + +/* + * _CORE_message_queue_Initialize + * + * This routine initializes a newly created message queue based on the + * specified data. + * + * Input parameters: + * the_message_queue - the message queue to initialize + * the_class - the API specific object class + * the_message_queue_attributes - the message queue's attributes + * maximum_pending_messages - maximum message and reserved buffer count + * maximum_message_size - maximum size of each message + * + * Output parameters: + * true - if the message queue is initialized + * false - if the message queue is NOT initialized + */ + +bool _CORE_message_queue_Initialize( + CORE_message_queue_Control *the_message_queue, + CORE_message_queue_Attributes *the_message_queue_attributes, + uint32_t maximum_pending_messages, + size_t maximum_message_size +) +{ + size_t message_buffering_required; + size_t allocated_message_size; + + the_message_queue->maximum_pending_messages = maximum_pending_messages; + the_message_queue->number_of_pending_messages = 0; + the_message_queue->maximum_message_size = maximum_message_size; + _CORE_message_queue_Set_notify( the_message_queue, NULL, NULL ); + + /* + * Round size up to multiple of a pointer for chain init and + * check for overflow on adding overhead to each message. + */ + allocated_message_size = maximum_message_size; + if (allocated_message_size & (sizeof(uint32_t) - 1)) { + allocated_message_size += sizeof(uint32_t); + allocated_message_size &= ~(sizeof(uint32_t) - 1); + } + + if (allocated_message_size < maximum_message_size) + return false; + + /* + * Calculate how much total memory is required for message buffering and + * check for overflow on the multiplication. + */ + message_buffering_required = (size_t) maximum_pending_messages * + (allocated_message_size + sizeof(CORE_message_queue_Buffer_control)); + + if (message_buffering_required < allocated_message_size) + return false; + + /* + * Attempt to allocate the message memory + */ + the_message_queue->message_buffers = (CORE_message_queue_Buffer *) + _Workspace_Allocate( message_buffering_required ); + + if (the_message_queue->message_buffers == 0) + return false; + + /* + * Initialize the pool of inactive messages, pending messages, + * and set of waiting threads. + */ + _Chain_Initialize ( + &the_message_queue->Inactive_messages, + the_message_queue->message_buffers, + (size_t) maximum_pending_messages, + allocated_message_size + sizeof( CORE_message_queue_Buffer_control ) + ); + + _Chain_Initialize_empty( &the_message_queue->Pending_messages ); + + _Thread_queue_Initialize( + &the_message_queue->Wait_queue, + _CORE_message_queue_Is_priority( the_message_queue_attributes ) ? + THREAD_QUEUE_DISCIPLINE_PRIORITY : THREAD_QUEUE_DISCIPLINE_FIFO, + STATES_WAITING_FOR_MESSAGE, + CORE_MESSAGE_QUEUE_STATUS_TIMEOUT + ); + + return true; +} diff --git a/cpukit/score/src/coremsgbroadcast.c b/cpukit/score/src/coremsgbroadcast.c new file mode 100644 index 0000000000..f8f76b0a38 --- /dev/null +++ b/cpukit/score/src/coremsgbroadcast.c @@ -0,0 +1,116 @@ +/* + * CORE Message Queue Handler + * + * DESCRIPTION: + * + * This package is the implementation of the CORE Message Queue Handler. + * This core object provides task synchronization and communication functions + * via messages passed to queue objects. + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/coremsg.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> + +/*PAGE + * + * _CORE_message_queue_Broadcast + * + * This function sends a message for every thread waiting on the queue and + * returns the number of threads made ready by the message. + * + * Input parameters: + * the_message_queue - message is submitted to this message queue + * buffer - pointer to message buffer + * size - size in bytes of message to send + * id - id of message queue + * api_message_queue_mp_support - api specific mp support callout + * count - area to store number of threads made ready + * + * Output parameters: + * count - number of threads made ready + * CORE_MESSAGE_QUEUE_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +CORE_message_queue_Status _CORE_message_queue_Broadcast( + CORE_message_queue_Control *the_message_queue, + const void *buffer, + size_t size, + #if defined(RTEMS_MULTIPROCESSING) + Objects_Id id, + CORE_message_queue_API_mp_support_callout api_message_queue_mp_support, + #else + Objects_Id id __attribute__((unused)), + CORE_message_queue_API_mp_support_callout api_message_queue_mp_support __attribute__((unused)), + #endif + uint32_t *count +) +{ + Thread_Control *the_thread; + uint32_t number_broadcasted; + Thread_Wait_information *waitp; + + if ( size > the_message_queue->maximum_message_size ) { + return CORE_MESSAGE_QUEUE_STATUS_INVALID_SIZE; + } + + /* + * If there are pending messages, then there can't be threads + * waiting for us to send them a message. + * + * NOTE: This check is critical because threads can block on + * send and receive and this ensures that we are broadcasting + * the message to threads waiting to receive -- not to send. + */ + + if ( the_message_queue->number_of_pending_messages != 0 ) { + *count = 0; + return CORE_MESSAGE_QUEUE_STATUS_SUCCESSFUL; + } + + /* + * There must be no pending messages if there is a thread waiting to + * receive a message. + */ + number_broadcasted = 0; + while ((the_thread = + _Thread_queue_Dequeue(&the_message_queue->Wait_queue))) { + waitp = &the_thread->Wait; + number_broadcasted += 1; + + _CORE_message_queue_Copy_buffer( + buffer, + waitp->return_argument_second.mutable_object, + size + ); + + *(size_t *) the_thread->Wait.return_argument = size; + + #if defined(RTEMS_MULTIPROCESSING) + if ( !_Objects_Is_local_id( the_thread->Object.id ) ) + (*api_message_queue_mp_support) ( the_thread, id ); + #endif + + } + *count = number_broadcasted; + return CORE_MESSAGE_QUEUE_STATUS_SUCCESSFUL; +} diff --git a/cpukit/score/src/coremsgclose.c b/cpukit/score/src/coremsgclose.c new file mode 100644 index 0000000000..b4622598b5 --- /dev/null +++ b/cpukit/score/src/coremsgclose.c @@ -0,0 +1,77 @@ +/* + * CORE Message Queue Handler + * + * DESCRIPTION: + * + * This package is the implementation of the CORE Message Queue Handler. + * This core object provides task synchronization and communication functions + * via messages passed to queue objects. + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/coremsg.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> + +/*PAGE + * + * _CORE_message_queue_Close + * + * This function closes a message by returning all allocated space and + * flushing the message_queue's task wait queue. + * + * Input parameters: + * the_message_queue - the message_queue to be flushed + * remote_extract_callout - function to invoke remotely + * status - status to pass to thread + * + * Output parameters: NONE + */ + +void _CORE_message_queue_Close( + CORE_message_queue_Control *the_message_queue, + Thread_queue_Flush_callout remote_extract_callout, + uint32_t status +) +{ + + /* + * This will flush blocked threads whether they were blocked on + * a send or receive. + */ + + _Thread_queue_Flush( + &the_message_queue->Wait_queue, + remote_extract_callout, + status + ); + + /* + * This removes all messages from the pending message queue. Since + * we just flushed all waiting threads, we don't have to worry about + * the flush satisfying any blocked senders as a side-effect. + */ + + if ( the_message_queue->number_of_pending_messages != 0 ) + (void) _CORE_message_queue_Flush_support( the_message_queue ); + + (void) _Workspace_Free( the_message_queue->message_buffers ); + +} diff --git a/cpukit/score/src/coremsgflush.c b/cpukit/score/src/coremsgflush.c new file mode 100644 index 0000000000..44bf059b89 --- /dev/null +++ b/cpukit/score/src/coremsgflush.c @@ -0,0 +1,55 @@ +/* + * CORE Message Queue Handler + * + * DESCRIPTION: + * + * This package is the implementation of the CORE Message Queue Handler. + * This core object provides task synchronization and communication functions + * via messages passed to queue objects. + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/coremsg.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> + +/*PAGE + * + * _CORE_message_queue_Flush + * + * This function flushes the message_queue's pending message queue. The + * number of messages flushed from the queue is returned. + * + * Input parameters: + * the_message_queue - the message_queue to be flushed + * + * Output parameters: + * returns - the number of messages flushed from the queue + */ + +uint32_t _CORE_message_queue_Flush( + CORE_message_queue_Control *the_message_queue +) +{ + if ( the_message_queue->number_of_pending_messages != 0 ) + return _CORE_message_queue_Flush_support( the_message_queue ); + else + return 0; +} diff --git a/cpukit/score/src/coremsgflushsupp.c b/cpukit/score/src/coremsgflushsupp.c new file mode 100644 index 0000000000..4e15e1a495 --- /dev/null +++ b/cpukit/score/src/coremsgflushsupp.c @@ -0,0 +1,106 @@ +/* + * CORE Message Queue Handler + * + * DESCRIPTION: + * + * This package is the implementation of the CORE Message Queue Handler. + * This core object provides task synchronization and communication functions + * via messages passed to queue objects. + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/coremsg.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> + +/*PAGE + * + * _CORE_message_queue_Flush_support + * + * This message handler routine removes all messages from a message queue + * and returns them to the inactive message pool. The number of messages + * flushed from the queue is returned + * + * Input parameters: + * the_message_queue - pointer to message queue + * + * Output parameters: + * returns - number of messages placed on inactive chain + * + * INTERRUPT LATENCY: + * only case + */ + +uint32_t _CORE_message_queue_Flush_support( + CORE_message_queue_Control *the_message_queue +) +{ + ISR_Level level; + Chain_Node *inactive_head; + Chain_Node *inactive_first; + Chain_Node *message_queue_first; + Chain_Node *message_queue_last; + uint32_t count; + + /* + * Currently, RTEMS supports no API that has both flush and blocking + * sends. Thus, this routine assumes that there are no senders + * blocked waiting to send messages. In the event, that an API is + * added that can flush a message queue when threads are blocked + * waiting to send, there are two basic behaviors envisioned: + * + * (1) The thread queue of pending senders is a logical extension + * of the pending message queue. In this case, it should be + * flushed using the _Thread_queue_Flush() service with a status + * such as CORE_MESSAGE_QUEUE_SENDER_FLUSHED (which currently does + * not exist). This can be implemented without changing the "big-O" + * of the message flushing part of the routine. + * + * (2) Only the actual messages queued should be purged. In this case, + * the blocked sender threads must be allowed to send their messages. + * In this case, the implementation will be forced to individually + * dequeue the senders and queue their messages. This will force + * this routine to have "big O(n)" where n is the number of blocked + * senders. If there are more messages pending than senders blocked, + * then the existing flush code can be used to dispose of the remaining + * pending messages. + * + * For now, though, we are very happy to have a small routine with + * fixed execution time that only deals with pending messages. + */ + + _ISR_Disable( level ); + inactive_head = _Chain_Head( &the_message_queue->Inactive_messages ); + inactive_first = inactive_head->next;; + message_queue_first = _Chain_First( &the_message_queue->Pending_messages ); + message_queue_last = _Chain_Last( &the_message_queue->Pending_messages ); + + inactive_head->next = message_queue_first; + message_queue_last->next = inactive_first; + inactive_first->previous = message_queue_last; + message_queue_first->previous = inactive_head; + + _Chain_Initialize_empty( &the_message_queue->Pending_messages ); + + count = the_message_queue->number_of_pending_messages; + the_message_queue->number_of_pending_messages = 0; + _ISR_Enable( level ); + return count; +} diff --git a/cpukit/score/src/coremsgflushwait.c b/cpukit/score/src/coremsgflushwait.c new file mode 100644 index 0000000000..d7b3c00f5f --- /dev/null +++ b/cpukit/score/src/coremsgflushwait.c @@ -0,0 +1,72 @@ +/* + * CORE Message Queue Handler + * + * DESCRIPTION: + * + * This package is the implementation of the CORE Message Queue Handler. + * This core object provides task synchronization and communication functions + * via messages passed to queue objects. + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/coremsg.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> + +#if defined(FUNCTIONALITY_NOT_CURRENTLY_USED_BY_ANY_API) + /*PAGE + * + * _CORE_message_queue_Flush_waiting_threads + * + * This function flushes the message_queue's task wait queue. The number + * of messages flushed from the queue is returned. + * + * Input parameters: + * the_message_queue - the message_queue to be flushed + * + * Output parameters: + * returns - the number of messages flushed from the queue + */ + + void _CORE_message_queue_Flush_waiting_threads( + CORE_message_queue_Control *the_message_queue + ) + { + /* XXX this is not supported for global message queues */ + + /* + * IF there are no pending messages, + * THEN threads may be blocked waiting to RECEIVE a message, + * + * IF the pending message queue is full + * THEN threads may be blocked waiting to SEND a message + * + * But in either case, we will return "unsatisfied nowait" + * to indicate that the blocking condition was not satisfied + * and that the blocking state was canceled. + */ + + _Thread_queue_Flush( + &the_message_queue->Wait_queue, + NULL, + CORE_MESSAGE_QUEUE_STATUS_UNSATISFIED_NOWAIT + ); + } +#endif diff --git a/cpukit/score/src/coremsginsert.c b/cpukit/score/src/coremsginsert.c new file mode 100644 index 0000000000..d333a5fb55 --- /dev/null +++ b/cpukit/score/src/coremsginsert.c @@ -0,0 +1,133 @@ +/* + * CORE Message Queue Handler + * + * DESCRIPTION: + * + * This package is the implementation of the CORE Message Queue Handler. + * This core object provides task synchronization and communication functions + * via messages passed to queue objects. + * + * COPYRIGHT (c) 1989-2005. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/coremsg.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> + +/*PAGE + * + * _CORE_message_queue_Insert_message + * + * This kernel routine inserts the specified message into the + * message queue. It is assumed that the message has been filled + * in before this routine is called. + * + * Input parameters: + * the_message_queue - pointer to message queue + * the_message - message to insert + * priority - insert indication + * + * Output parameters: NONE + * + * INTERRUPT LATENCY: + * insert + */ + +void _CORE_message_queue_Insert_message( + CORE_message_queue_Control *the_message_queue, + CORE_message_queue_Buffer_control *the_message, + CORE_message_queue_Submit_types submit_type +) +{ + ISR_Level level; + #if defined(RTEMS_SCORE_COREMSG_ENABLE_NOTIFICATION) + bool notify = false; + #define SET_NOTIFY() \ + do { \ + if ( the_message_queue->number_of_pending_messages == 0 ) \ + notify = true; \ + } while (0) + #else + #define SET_NOTIFY() + #endif + + _CORE_message_queue_Set_message_priority( the_message, submit_type ); + + #if !defined(RTEMS_SCORE_COREMSG_ENABLE_MESSAGE_PRIORITY) + _ISR_Disable( level ); + SET_NOTIFY(); + the_message_queue->number_of_pending_messages++; + if ( submit_type == CORE_MESSAGE_QUEUE_SEND_REQUEST ) + _CORE_message_queue_Append_unprotected(the_message_queue, the_message); + else + _CORE_message_queue_Prepend_unprotected(the_message_queue, the_message); + _ISR_Enable( level ); + #else + if ( submit_type == CORE_MESSAGE_QUEUE_SEND_REQUEST ) { + _ISR_Disable( level ); + SET_NOTIFY(); + the_message_queue->number_of_pending_messages++; + _CORE_message_queue_Append_unprotected(the_message_queue, the_message); + _ISR_Enable( level ); + } else if ( submit_type == CORE_MESSAGE_QUEUE_URGENT_REQUEST ) { + _ISR_Disable( level ); + SET_NOTIFY(); + the_message_queue->number_of_pending_messages++; + _CORE_message_queue_Prepend_unprotected(the_message_queue, the_message); + _ISR_Enable( level ); + } else { + CORE_message_queue_Buffer_control *this_message; + Chain_Node *the_node; + Chain_Control *the_header; + int the_priority; + + the_priority = _CORE_message_queue_Get_message_priority(the_message); + the_header = &the_message_queue->Pending_messages; + the_node = _Chain_First( the_header ); + while ( !_Chain_Is_tail( the_header, the_node ) ) { + int this_priority; + + this_message = (CORE_message_queue_Buffer_control *) the_node; + + this_priority = _CORE_message_queue_Get_message_priority(this_message); + + if ( this_priority <= the_priority ) { + the_node = the_node->next; + continue; + } + break; + } + _ISR_Disable( level ); + SET_NOTIFY(); + the_message_queue->number_of_pending_messages++; + _Chain_Insert_unprotected( the_node->previous, &the_message->Node ); + _ISR_Enable( level ); + } + #endif + + #if defined(RTEMS_SCORE_COREMSG_ENABLE_NOTIFICATION) + /* + * According to POSIX, does this happen before or after the message + * is actually enqueued. It is logical to think afterwards, because + * the message is actually in the queue at this point. + */ + if ( notify && the_message_queue->notify_handler ) + (*the_message_queue->notify_handler)(the_message_queue->notify_argument); + #endif +} diff --git a/cpukit/score/src/coremsgseize.c b/cpukit/score/src/coremsgseize.c new file mode 100644 index 0000000000..9a9fd75567 --- /dev/null +++ b/cpukit/score/src/coremsgseize.c @@ -0,0 +1,157 @@ +/* + * CORE Message Queue Handler + * + * DESCRIPTION: + * + * This package is the implementation of the CORE Message Queue Handler. + * This core object provides task synchronization and communication functions + * via messages passed to queue objects. + * + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/coremsg.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> + +/*PAGE + * + * _CORE_message_queue_Seize + * + * This kernel routine dequeues a message, copies the message buffer to + * a given destination buffer, and frees the message buffer to the + * inactive message pool. The thread will be blocked if wait is true, + * otherwise an error will be given to the thread if no messages are available. + * + * Input parameters: + * the_message_queue - pointer to message queue + * id - id of object we are waitig on + * buffer - pointer to message buffer to be filled + * size_p - pointer to the size of buffer to be filled + * wait - true if wait is allowed, false otherwise + * timeout - time to wait for a message + * + * Output parameters: NONE + * + * NOTE: Dependent on BUFFER_LENGTH + * + * INTERRUPT LATENCY: + * available + * wait + */ + +void _CORE_message_queue_Seize( + CORE_message_queue_Control *the_message_queue, + Objects_Id id, + void *buffer, + size_t *size_p, + bool wait, + Watchdog_Interval timeout +) +{ + ISR_Level level; + CORE_message_queue_Buffer_control *the_message; + Thread_Control *executing; + + executing = _Thread_Executing; + executing->Wait.return_code = CORE_MESSAGE_QUEUE_STATUS_SUCCESSFUL; + _ISR_Disable( level ); + the_message = _CORE_message_queue_Get_pending_message( the_message_queue ); + if ( the_message != NULL ) { + the_message_queue->number_of_pending_messages -= 1; + _ISR_Enable( level ); + + *size_p = the_message->Contents.size; + _Thread_Executing->Wait.count = + _CORE_message_queue_Get_message_priority( the_message ); + _CORE_message_queue_Copy_buffer( + the_message->Contents.buffer, + buffer, + *size_p + ); + + #if !defined(RTEMS_SCORE_COREMSG_ENABLE_BLOCKING_SEND) + /* + * There is not an API with blocking sends enabled. + * So return immediately. + */ + _CORE_message_queue_Free_message_buffer(the_message_queue, the_message); + return; + #else + { + Thread_Control *the_thread; + + /* + * There could be a thread waiting to send a message. If there + * is not, then we can go ahead and free the buffer. + * + * NOTE: If we note that the queue was not full before this receive, + * then we can avoid this dequeue. + */ + the_thread = _Thread_queue_Dequeue( &the_message_queue->Wait_queue ); + if ( !the_thread ) { + _CORE_message_queue_Free_message_buffer( + the_message_queue, + the_message + ); + return; + } + + /* + * There was a thread waiting to send a message. This code + * puts the messages in the message queue on behalf of the + * waiting task. + */ + _CORE_message_queue_Set_message_priority( + the_message, + the_thread->Wait.count + ); + the_message->Contents.size = (size_t) the_thread->Wait.option; + _CORE_message_queue_Copy_buffer( + the_thread->Wait.return_argument_second.immutable_object, + the_message->Contents.buffer, + the_message->Contents.size + ); + + _CORE_message_queue_Insert_message( + the_message_queue, + the_message, + _CORE_message_queue_Get_message_priority( the_message ) + ); + return; + } + #endif + } + + if ( !wait ) { + _ISR_Enable( level ); + executing->Wait.return_code = CORE_MESSAGE_QUEUE_STATUS_UNSATISFIED_NOWAIT; + return; + } + + _Thread_queue_Enter_critical_section( &the_message_queue->Wait_queue ); + executing->Wait.queue = &the_message_queue->Wait_queue; + executing->Wait.id = id; + executing->Wait.return_argument_second.mutable_object = buffer; + executing->Wait.return_argument = size_p; + /* Wait.count will be filled in with the message priority */ + _ISR_Enable( level ); + + _Thread_queue_Enqueue( &the_message_queue->Wait_queue, timeout ); +} diff --git a/cpukit/score/src/coremsgsubmit.c b/cpukit/score/src/coremsgsubmit.c new file mode 100644 index 0000000000..c67157dc44 --- /dev/null +++ b/cpukit/score/src/coremsgsubmit.c @@ -0,0 +1,180 @@ +/* + * CORE Message Queue Handler + * + * DESCRIPTION: + * + * This package is the implementation of the CORE Message Queue Handler. + * This core object provides task synchronization and communication functions + * via messages passed to queue objects. + * + * COPYRIGHT (c) 1989-2009. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/coremsg.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> + +/*PAGE + * + * _CORE_message_queue_Submit + * + * This routine implements the send and urgent message functions. It + * processes a message that is to be submitted to the designated + * message queue. The message will either be processed as a + * send message which it will be inserted at the rear of the queue + * or it will be processed as an urgent message which will be inserted + * at the front of the queue. + * + * Input parameters: + * the_message_queue - message is submitted to this message queue + * buffer - pointer to message buffer + * size - size in bytes of message to send + * id - id of message queue + * api_message_queue_mp_support - api specific mp support callout + * submit_type - send or urgent message + * + * Output parameters: + * CORE_MESSAGE_QUEUE_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +CORE_message_queue_Status _CORE_message_queue_Submit( + CORE_message_queue_Control *the_message_queue, + const void *buffer, + size_t size, + Objects_Id id, + #if defined(RTEMS_MULTIPROCESSING) + CORE_message_queue_API_mp_support_callout api_message_queue_mp_support, + #else + CORE_message_queue_API_mp_support_callout api_message_queue_mp_support __attribute__((unused)), + #endif + CORE_message_queue_Submit_types submit_type, + bool wait, + Watchdog_Interval timeout +) +{ + CORE_message_queue_Buffer_control *the_message; + Thread_Control *the_thread; + + if ( size > the_message_queue->maximum_message_size ) { + return CORE_MESSAGE_QUEUE_STATUS_INVALID_SIZE; + } + + /* + * Is there a thread currently waiting on this message queue? + */ + if ( the_message_queue->number_of_pending_messages == 0 ) { + the_thread = _Thread_queue_Dequeue( &the_message_queue->Wait_queue ); + if ( the_thread ) { + _CORE_message_queue_Copy_buffer( + buffer, + the_thread->Wait.return_argument_second.mutable_object, + size + ); + *(size_t *) the_thread->Wait.return_argument = size; + the_thread->Wait.count = (uint32_t) submit_type; + + #if defined(RTEMS_MULTIPROCESSING) + if ( !_Objects_Is_local_id( the_thread->Object.id ) ) + (*api_message_queue_mp_support) ( the_thread, id ); + #endif + return CORE_MESSAGE_QUEUE_STATUS_SUCCESSFUL; + } + } + + /* + * No one waiting on the message queue at this time, so attempt to + * queue the message up for a future receive. + */ + if ( the_message_queue->number_of_pending_messages < + the_message_queue->maximum_pending_messages ) { + + the_message = + _CORE_message_queue_Allocate_message_buffer( the_message_queue ); + + #if defined(RTEMS_DEBUG) + /* + * NOTE: If the system is consistent, this error should never occur. + */ + + if ( !the_message ) + return CORE_MESSAGE_QUEUE_STATUS_UNSATISFIED; + #endif + + _CORE_message_queue_Copy_buffer( + buffer, + the_message->Contents.buffer, + size + ); + the_message->Contents.size = size; + _CORE_message_queue_Set_message_priority( the_message, submit_type ); + + _CORE_message_queue_Insert_message( + the_message_queue, + the_message, + submit_type + ); + return CORE_MESSAGE_QUEUE_STATUS_SUCCESSFUL; + } + + #if !defined(RTEMS_SCORE_COREMSG_ENABLE_BLOCKING_SEND) + return CORE_MESSAGE_QUEUE_STATUS_TOO_MANY; + #else + /* + * No message buffers were available so we may need to return an + * overflow error or block the sender until the message is placed + * on the queue. + */ + if ( !wait ) { + return CORE_MESSAGE_QUEUE_STATUS_TOO_MANY; + } + + /* + * Do NOT block on a send if the caller is in an ISR. It is + * deadly to block in an ISR. + */ + if ( _ISR_Is_in_progress() ) { + return CORE_MESSAGE_QUEUE_STATUS_UNSATISFIED; + } + + /* + * WARNING!! executing should NOT be used prior to this point. + * Thus the unusual choice to open a new scope and declare + * it as a variable. Doing this emphasizes how dangerous it + * would be to use this variable prior to here. + */ + { + Thread_Control *executing = _Thread_Executing; + ISR_Level level; + + _ISR_Disable( level ); + _Thread_queue_Enter_critical_section( &the_message_queue->Wait_queue ); + executing->Wait.queue = &the_message_queue->Wait_queue; + executing->Wait.id = id; + executing->Wait.return_argument_second.immutable_object = buffer; + executing->Wait.option = (uint32_t) size; + executing->Wait.count = submit_type; + _ISR_Enable( level ); + + _Thread_queue_Enqueue( &the_message_queue->Wait_queue, timeout ); + } + + return CORE_MESSAGE_QUEUE_STATUS_UNSATISFIED_WAIT; + #endif +} diff --git a/cpukit/score/src/coremutex.c b/cpukit/score/src/coremutex.c new file mode 100644 index 0000000000..dcd2e778fe --- /dev/null +++ b/cpukit/score/src/coremutex.c @@ -0,0 +1,94 @@ +/* + * Mutex Handler + * + * DESCRIPTION: + * + * This package is the implementation of the Mutex Handler. + * This handler provides synchronization and mutual exclusion capabilities. + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/coremutex.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> + +/*PAGE + * + * _CORE_mutex_Initialize + * + * This routine initializes a mutex at create time and set the control + * structure according to the values passed. + * + * Input parameters: + * the_mutex - the mutex control block to initialize + * the_mutex_attributes - the mutex attributes specified at create time + * initial_lock - mutex initial lock or unlocked status + * + * Output parameters: NONE + */ + +CORE_mutex_Status _CORE_mutex_Initialize( + CORE_mutex_Control *the_mutex, + CORE_mutex_Attributes *the_mutex_attributes, + uint32_t initial_lock +) +{ + +/* Add this to the RTEMS environment later ????????? + rtems_assert( initial_lock == CORE_MUTEX_LOCKED || + initial_lock == CORE_MUTEX_UNLOCKED ); + */ + + the_mutex->Attributes = *the_mutex_attributes; + the_mutex->lock = initial_lock; + the_mutex->blocked_count = 0; + + if ( initial_lock == CORE_MUTEX_LOCKED ) { + the_mutex->nest_count = 1; + the_mutex->holder = _Thread_Executing; + the_mutex->holder_id = _Thread_Executing->Object.id; + if ( _CORE_mutex_Is_inherit_priority( &the_mutex->Attributes ) || + _CORE_mutex_Is_priority_ceiling( &the_mutex->Attributes ) ) { + + if ( _Thread_Executing->current_priority < + the_mutex->Attributes.priority_ceiling ) + return CORE_MUTEX_STATUS_CEILING_VIOLATED; +#ifdef __RTEMS_STRICT_ORDER_MUTEX__ + _Chain_Prepend_unprotected( &_Thread_Executing->lock_mutex, + &the_mutex->queue.lock_queue ); + the_mutex->queue.priority_before = _Thread_Executing->current_priority; +#endif + + _Thread_Executing->resource_count++; + } + } else { + the_mutex->nest_count = 0; + the_mutex->holder = NULL; + the_mutex->holder_id = 0; + } + + _Thread_queue_Initialize( + &the_mutex->Wait_queue, + _CORE_mutex_Is_fifo( the_mutex_attributes ) ? + THREAD_QUEUE_DISCIPLINE_FIFO : THREAD_QUEUE_DISCIPLINE_PRIORITY, + STATES_WAITING_FOR_MUTEX, + CORE_MUTEX_TIMEOUT + ); + + return CORE_MUTEX_STATUS_SUCCESSFUL; +} diff --git a/cpukit/score/src/coremutexflush.c b/cpukit/score/src/coremutexflush.c new file mode 100644 index 0000000000..2006f2dee8 --- /dev/null +++ b/cpukit/score/src/coremutexflush.c @@ -0,0 +1,55 @@ +/* + * Mutex Handler + * + * DESCRIPTION: + * + * This package is the implementation of the Mutex Handler. + * This handler provides synchronization and mutual exclusion capabilities. + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/coremutex.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> + +/*PAGE + * + * _CORE_mutex_Flush + * + * This function a flushes the mutex's task wait queue. + * + * Input parameters: + * the_mutex - the mutex to be flushed + * remote_extract_callout - function to invoke remotely + * status - status to pass to thread + * + * Output parameters: NONE + */ + +void _CORE_mutex_Flush( + CORE_mutex_Control *the_mutex, + Thread_queue_Flush_callout remote_extract_callout, + uint32_t status +) +{ + _Thread_queue_Flush( + &the_mutex->Wait_queue, + remote_extract_callout, + status + ); +} diff --git a/cpukit/score/src/coremutexseize.c b/cpukit/score/src/coremutexseize.c new file mode 100644 index 0000000000..db6d513cb4 --- /dev/null +++ b/cpukit/score/src/coremutexseize.c @@ -0,0 +1,78 @@ +/* + * Mutex Handler + * + * DESCRIPTION: + * + * This package is the implementation of the Mutex Handler. + * This handler provides synchronization and mutual exclusion capabilities. + * + * COPYRIGHT (c) 1989-2006. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/coremutex.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> + +#if defined(__RTEMS_DO_NOT_INLINE_CORE_MUTEX_SEIZE__) +void _CORE_mutex_Seize( + CORE_mutex_Control *_the_mutex, + Objects_Id _id, + bool _wait, + Watchdog_Interval _timeout, + ISR_Level _level +) +{ + _CORE_mutex_Seize_body( _the_mutex, _id, _wait, _timeout, _level ); +} +#endif + +/*PAGE + * + * _CORE_mutex_Seize (interrupt blocking support) + * + * This routine blocks the caller thread after an attempt attempts to obtain + * the specified mutex has failed. + * + * Input parameters: + * the_mutex - pointer to mutex control block + * timeout - number of ticks to wait (0 means forever) + */ + +void _CORE_mutex_Seize_interrupt_blocking( + CORE_mutex_Control *the_mutex, + Watchdog_Interval timeout +) +{ + Thread_Control *executing; + + executing = _Thread_Executing; + if ( _CORE_mutex_Is_inherit_priority( &the_mutex->Attributes ) ) { + if ( the_mutex->holder->current_priority > executing->current_priority ) { + _Thread_Change_priority( + the_mutex->holder, + executing->current_priority, + false + ); + } + } + + the_mutex->blocked_count++; + _Thread_queue_Enqueue( &the_mutex->Wait_queue, timeout ); + + _Thread_Enable_dispatch(); +} + diff --git a/cpukit/score/src/coremutexseizeintr.c b/cpukit/score/src/coremutexseizeintr.c new file mode 100644 index 0000000000..4e4e5c4a07 --- /dev/null +++ b/cpukit/score/src/coremutexseizeintr.c @@ -0,0 +1,33 @@ +/* + * Mutex Handler -- Seize interrupt disable version + * + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/coremutex.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> + +#if defined(__RTEMS_DO_NOT_INLINE_CORE_MUTEX_SEIZE__) +int _CORE_mutex_Seize_interrupt_trylock( + CORE_mutex_Control *the_mutex, + ISR_Level *level_p +) +{ + return _CORE_mutex_Seize_interrupt_trylock_body( the_mutex, level_p ); +} +#endif diff --git a/cpukit/score/src/coremutexsurrender.c b/cpukit/score/src/coremutexsurrender.c new file mode 100644 index 0000000000..7e1a444215 --- /dev/null +++ b/cpukit/score/src/coremutexsurrender.c @@ -0,0 +1,231 @@ +/* + * Mutex Handler + * + * DESCRIPTION: + * + * This package is the implementation of the Mutex Handler. + * This handler provides synchronization and mutual exclusion capabilities. + * + * COPYRIGHT (c) 1989-2006. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/coremutex.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> + +#ifdef __RTEMS_STRICT_ORDER_MUTEX__ + static inline void _CORE_mutex_Push_priority( + CORE_mutex_Control *mutex, + Thread_Control *thread + ) + { + _Chain_Prepend_unprotected( + &thread->lock_mutex, + &mutex->queue.lock_queue + ); + mutex->queue.priority_before = thread->current_priority; + } + + static inline CORE_mutex_Status _CORE_mutex_Pop_priority( + CORE_mutex_Control *mutex, + Thread_Control *holder + ) + { + /* + * Check whether the holder release the mutex in LIFO order if not return + * error code. + */ + if ( _Chain_First( holder->lock_mutex ) != &mutex->queue.lock_queue ) { + mutex->nest_count++; + + return CORE_MUTEX_RELEASE_NOT_ORDER; + } + + /* + * This pops the first node from the list. + */ + _Chain_Get_first_unprotected( &holder->lock_mutex ); + + if ( mutex->queue.priority_before != holder->current_priority ) + _Thread_Change_priority( holder, mutex->queue.priority_before, true ); + + return CORE_MUTEX_STATUS_SUCCESSFUL; + } +#else + #define _CORE_mutex_Push_priority( mutex, thread ) ((void) 0) + + #define _CORE_mutex_Pop_priority( mutex, thread ) \ + CORE_MUTEX_STATUS_SUCCESSFUL +#endif + +/* + * _CORE_mutex_Surrender + * + * DESCRIPTION: + * + * This routine frees a unit to the mutex. If a task was blocked waiting for + * a unit from this mutex, then that task will be readied and the unit + * given to that task. Otherwise, the unit will be returned to the mutex. + * + * Input parameters: + * the_mutex - the mutex to be flushed + * id - id of parent mutex + * api_mutex_mp_support - api dependent MP support actions + * + * Output parameters: + * CORE_MUTEX_STATUS_SUCCESSFUL - if successful + * core error code - if unsuccessful + */ + +CORE_mutex_Status _CORE_mutex_Surrender( + CORE_mutex_Control *the_mutex, +#if defined(RTEMS_MULTIPROCESSING) + Objects_Id id, + CORE_mutex_API_mp_support_callout api_mutex_mp_support +#else + Objects_Id id __attribute__((unused)), + CORE_mutex_API_mp_support_callout api_mutex_mp_support __attribute__((unused)) +#endif +) +{ + Thread_Control *the_thread; + Thread_Control *holder; + + holder = the_mutex->holder; + + /* + * The following code allows a thread (or ISR) other than the thread + * which acquired the mutex to release that mutex. This is only + * allowed when the mutex in quetion is FIFO or simple Priority + * discipline. But Priority Ceiling or Priority Inheritance mutexes + * must be released by the thread which acquired them. + */ + + if ( the_mutex->Attributes.only_owner_release ) { + if ( !_Thread_Is_executing( holder ) ) + return CORE_MUTEX_STATUS_NOT_OWNER_OF_RESOURCE; + } + + /* XXX already unlocked -- not right status */ + + if ( !the_mutex->nest_count ) + return CORE_MUTEX_STATUS_SUCCESSFUL; + + the_mutex->nest_count--; + + if ( the_mutex->nest_count != 0 ) { + /* + * All error checking is on the locking side, so if the lock was + * allowed to acquired multiple times, then we should just deal with + * that. The RTEMS_DEBUG is just a validation. + */ + #if defined(RTEMS_DEBUG) + switch ( the_mutex->Attributes.lock_nesting_behavior ) { + case CORE_MUTEX_NESTING_ACQUIRES: + return CORE_MUTEX_STATUS_SUCCESSFUL; + #if defined(RTEMS_POSIX_API) + case CORE_MUTEX_NESTING_IS_ERROR: + /* should never occur */ + return CORE_MUTEX_STATUS_NESTING_NOT_ALLOWED; + #endif + case CORE_MUTEX_NESTING_BLOCKS: + /* Currently no API exercises this behavior. */ + break; + } + #else + /* must be CORE_MUTEX_NESTING_ACQUIRES or we wouldn't be here */ + return CORE_MUTEX_STATUS_SUCCESSFUL; + #endif + } + + /* + * Formally release the mutex before possibly transferring it to a + * blocked thread. + */ + if ( _CORE_mutex_Is_inherit_priority( &the_mutex->Attributes ) || + _CORE_mutex_Is_priority_ceiling( &the_mutex->Attributes ) ) { + CORE_mutex_Status pop_status = + _CORE_mutex_Pop_priority( the_mutex, holder ); + + if ( pop_status != CORE_MUTEX_STATUS_SUCCESSFUL ) + return pop_status; + + holder->resource_count--; + + /* + * Whether or not someone is waiting for the mutex, an + * inherited priority must be lowered if this is the last + * mutex (i.e. resource) this task has. + */ + if ( holder->resource_count == 0 && + holder->real_priority != holder->current_priority ) { + _Thread_Change_priority( holder, holder->real_priority, true ); + } + } + the_mutex->holder = NULL; + the_mutex->holder_id = 0; + + /* + * Now we check if another thread was waiting for this mutex. If so, + * transfer the mutex to that thread. + */ + if ( ( the_thread = _Thread_queue_Dequeue( &the_mutex->Wait_queue ) ) ) { + +#if defined(RTEMS_MULTIPROCESSING) + if ( !_Objects_Is_local_id( the_thread->Object.id ) ) { + + the_mutex->holder = NULL; + the_mutex->holder_id = the_thread->Object.id; + the_mutex->nest_count = 1; + + ( *api_mutex_mp_support)( the_thread, id ); + + } else +#endif + { + + the_mutex->holder = the_thread; + the_mutex->holder_id = the_thread->Object.id; + the_mutex->nest_count = 1; + + switch ( the_mutex->Attributes.discipline ) { + case CORE_MUTEX_DISCIPLINES_FIFO: + case CORE_MUTEX_DISCIPLINES_PRIORITY: + break; + case CORE_MUTEX_DISCIPLINES_PRIORITY_INHERIT: + _CORE_mutex_Push_priority( the_mutex, the_thread ); + the_thread->resource_count++; + break; + case CORE_MUTEX_DISCIPLINES_PRIORITY_CEILING: + _CORE_mutex_Push_priority( the_mutex, the_thread ); + the_thread->resource_count++; + if (the_mutex->Attributes.priority_ceiling < + the_thread->current_priority){ + _Thread_Change_priority( + the_thread, + the_mutex->Attributes.priority_ceiling, + false + ); + } + break; + } + } + } else + the_mutex->lock = CORE_MUTEX_UNLOCKED; + + return CORE_MUTEX_STATUS_SUCCESSFUL; +} diff --git a/cpukit/score/src/corerwlock.c b/cpukit/score/src/corerwlock.c new file mode 100644 index 0000000000..7bc988514e --- /dev/null +++ b/cpukit/score/src/corerwlock.c @@ -0,0 +1,61 @@ +/* + * SuperCore RWLock Handler + * + * DESCRIPTION: + * + * This package is part of the implementation of the SuperCore RWLock Handler. + * + * COPYRIGHT (c) 1989-2006. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/corerwlock.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> + +/*PAGE + * + * _CORE_RWLock_Initialize + * + * This function initialize a rwlock and sets the initial value based + * on the given count. + * + * Input parameters: + * the_rwlock - the rwlock control block to initialize + * the_rwlock_attributes - the attributes specified at create time + * + * Output parameters: NONE + */ + +void _CORE_RWLock_Initialize( + CORE_RWLock_Control *the_rwlock, + CORE_RWLock_Attributes *the_rwlock_attributes +) +{ + + the_rwlock->Attributes = *the_rwlock_attributes; +/* + the_rwlock->number_of_waiting_threads = 0; +*/ + the_rwlock->number_of_readers = 0; + the_rwlock->current_state = CORE_RWLOCK_UNLOCKED; + + _Thread_queue_Initialize( + &the_rwlock->Wait_queue, + THREAD_QUEUE_DISCIPLINE_FIFO, + STATES_WAITING_FOR_RWLOCK, + CORE_RWLOCK_TIMEOUT + ); +} diff --git a/cpukit/score/src/corerwlockobtainread.c b/cpukit/score/src/corerwlockobtainread.c new file mode 100644 index 0000000000..78b6ebc187 --- /dev/null +++ b/cpukit/score/src/corerwlockobtainread.c @@ -0,0 +1,108 @@ +/* + * SuperCore RWLock Handler -- Obtain RWLock for reading + * + * COPYRIGHT (c) 1989-2006. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/corerwlock.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/watchdog.h> + +/*PAGE + * + * _CORE_rwlock_Obtain_for_reading + * + * This function waits for the rwlock to become available. Optionally, + * a limit may be placed on the duration of the spin. + * + * Input parameters: + * the_rwlock - the rwlock control block to initialize + * timeout_allowed - true if timeout allowed + * timeout - the maximum number of ticks to spin + * + * Output parameters: NONE + */ + +void _CORE_RWLock_Obtain_for_reading( + CORE_RWLock_Control *the_rwlock, + Objects_Id id, + bool wait, + Watchdog_Interval timeout, + CORE_RWLock_API_mp_support_callout api_rwlock_mp_support +) +{ + ISR_Level level; + Thread_Control *executing = _Thread_Executing; + + /* + * If unlocked, then OK to read. + * If locked for reading and no waiters, then OK to read. + * If any thread is waiting, then we wait. + */ + + _ISR_Disable( level ); + switch ( the_rwlock->current_state ) { + case CORE_RWLOCK_UNLOCKED: + the_rwlock->current_state = CORE_RWLOCK_LOCKED_FOR_READING; + the_rwlock->number_of_readers += 1; + _ISR_Enable( level ); + executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL; + return; + + case CORE_RWLOCK_LOCKED_FOR_READING: { + Thread_Control *waiter; + waiter = _Thread_queue_First( &the_rwlock->Wait_queue ); + if ( !waiter ) { + the_rwlock->number_of_readers += 1; + _ISR_Enable( level ); + executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL; + return; + } + break; + } + case CORE_RWLOCK_LOCKED_FOR_WRITING: + break; + } + + /* + * If the thread is not willing to wait, then return immediately. + */ + + if ( !wait ) { + _ISR_Enable( level ); + executing->Wait.return_code = CORE_RWLOCK_UNAVAILABLE; + return; + } + + /* + * We need to wait to enter this critical section + */ + + _Thread_queue_Enter_critical_section( &the_rwlock->Wait_queue ); + executing->Wait.queue = &the_rwlock->Wait_queue; + executing->Wait.id = id; + executing->Wait.option = CORE_RWLOCK_THREAD_WAITING_FOR_READ; + executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL; + _ISR_Enable( level ); + + _Thread_queue_Enqueue_with_handler( + &the_rwlock->Wait_queue, + timeout, + _CORE_RWLock_Timeout + ); + + /* return to API level so it can dispatch and we block */ +} diff --git a/cpukit/score/src/corerwlockobtainwrite.c b/cpukit/score/src/corerwlockobtainwrite.c new file mode 100644 index 0000000000..c3aae6e34c --- /dev/null +++ b/cpukit/score/src/corerwlockobtainwrite.c @@ -0,0 +1,99 @@ +/* + * SuperCore RWLock Handler -- Obtain RWLock for writing + * + * COPYRIGHT (c) 1989-2006. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/corerwlock.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/watchdog.h> + +/*PAGE + * + * _CORE_rwlock_Obtain_for_writing + * + * This function waits for the rwlock to become available. Optionally, + * a limit may be placed on the duration of the spin. + * + * Input parameters: + * the_rwlock - the rwlock control block to initialize + * timeout_allowed - true if timeout allowed + * timeout - the maximum number of ticks to spin + * + * Output parameters: NONE + */ + +void _CORE_RWLock_Obtain_for_writing( + CORE_RWLock_Control *the_rwlock, + Objects_Id id, + bool wait, + Watchdog_Interval timeout, + CORE_RWLock_API_mp_support_callout api_rwlock_mp_support +) +{ + ISR_Level level; + Thread_Control *executing = _Thread_Executing; + + /* + * If unlocked, then OK to read. + * Otherwise, we have to block. + * If locked for reading and no waiters, then OK to read. + * If any thread is waiting, then we wait. + */ + + _ISR_Disable( level ); + switch ( the_rwlock->current_state ) { + case CORE_RWLOCK_UNLOCKED: + the_rwlock->current_state = CORE_RWLOCK_LOCKED_FOR_WRITING; + _ISR_Enable( level ); + executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL; + return; + + case CORE_RWLOCK_LOCKED_FOR_READING: + case CORE_RWLOCK_LOCKED_FOR_WRITING: + break; + } + + /* + * If the thread is not willing to wait, then return immediately. + */ + + if ( !wait ) { + _ISR_Enable( level ); + executing->Wait.return_code = CORE_RWLOCK_UNAVAILABLE; + return; + } + + /* + * We need to wait to enter this critical section + */ + + _Thread_queue_Enter_critical_section( &the_rwlock->Wait_queue ); + executing->Wait.queue = &the_rwlock->Wait_queue; + executing->Wait.id = id; + executing->Wait.option = CORE_RWLOCK_THREAD_WAITING_FOR_WRITE; + executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL; + _ISR_Enable( level ); + + _Thread_queue_Enqueue_with_handler( + &the_rwlock->Wait_queue, + timeout, + _CORE_RWLock_Timeout + ); + + + /* return to API level so it can dispatch and we block */ +} diff --git a/cpukit/score/src/corerwlockrelease.c b/cpukit/score/src/corerwlockrelease.c new file mode 100644 index 0000000000..379fdebdec --- /dev/null +++ b/cpukit/score/src/corerwlockrelease.c @@ -0,0 +1,106 @@ +/* + * SuperCore RWLock Handler -- Release a RWLock + * + * COPYRIGHT (c) 1989-2006. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/corerwlock.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/watchdog.h> + +/*PAGE + * + * _CORE_RWLock_Release + * + * This function releases the rwlock. + * + * Input parameters: + * the_rwlock - the rwlock control block to initialize + * + * Output parameters: NONE + */ + +CORE_RWLock_Status _CORE_RWLock_Release( + CORE_RWLock_Control *the_rwlock +) +{ + ISR_Level level; + Thread_Control *executing = _Thread_Executing; + Thread_Control *next; + + /* + * If unlocked, then OK to read. + * Otherwise, we have to block. + * If locked for reading and no waiters, then OK to read. + * If any thread is waiting, then we wait. + */ + + _ISR_Disable( level ); + if ( the_rwlock->current_state == CORE_RWLOCK_UNLOCKED){ + _ISR_Enable( level ); + executing->Wait.return_code = CORE_RWLOCK_UNAVAILABLE; + return CORE_RWLOCK_SUCCESSFUL; + } + if ( the_rwlock->current_state == CORE_RWLOCK_LOCKED_FOR_READING ) { + the_rwlock->number_of_readers -= 1; + if ( the_rwlock->number_of_readers != 0 ) { + /* must be unlocked again */ + _ISR_Enable( level ); + return CORE_RWLOCK_SUCCESSFUL; + } + } + + /* CORE_RWLOCK_LOCKED_FOR_WRITING or READING with readers */ + executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL; + + /* + * Implicitly transition to "unlocked" and find another thread interested + * in obtaining this rwlock. + */ + the_rwlock->current_state = CORE_RWLOCK_UNLOCKED; + _ISR_Enable( level ); + + next = _Thread_queue_Dequeue( &the_rwlock->Wait_queue ); + + if ( next ) { + if ( next->Wait.option == CORE_RWLOCK_THREAD_WAITING_FOR_WRITE ) { + the_rwlock->current_state = CORE_RWLOCK_LOCKED_FOR_WRITING; + return CORE_RWLOCK_SUCCESSFUL; + } + + /* + * Must be CORE_RWLOCK_THREAD_WAITING_FOR_READING + */ + the_rwlock->number_of_readers += 1; + the_rwlock->current_state = CORE_RWLOCK_LOCKED_FOR_READING; + + /* + * Now see if more readers can be let go. + */ + while ( 1 ) { + next = _Thread_queue_First( &the_rwlock->Wait_queue ); + if ( !next || + next->Wait.option == CORE_RWLOCK_THREAD_WAITING_FOR_WRITE ) + return CORE_RWLOCK_SUCCESSFUL; + the_rwlock->number_of_readers += 1; + _Thread_queue_Extract( &the_rwlock->Wait_queue, next ); + } + } + + /* indentation is to match _ISR_Disable at top */ + + return CORE_RWLOCK_SUCCESSFUL; +} diff --git a/cpukit/score/src/corerwlocktimeout.c b/cpukit/score/src/corerwlocktimeout.c new file mode 100644 index 0000000000..698b3f8095 --- /dev/null +++ b/cpukit/score/src/corerwlocktimeout.c @@ -0,0 +1,55 @@ +/* + * Thread Queue Handler + * + * + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/corerwlock.h> +#include <rtems/score/corerwlock.h> + +/* + * _CORE_RWLock_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 _CORE_RWLock_Timeout( + Objects_Id id, + void *ignored +) +{ + Thread_Control *the_thread; + Objects_Locations location; + + the_thread = _Thread_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: +#if defined(RTEMS_MULTIPROCESSING) + case OBJECTS_REMOTE: /* impossible */ +#endif + break; + case OBJECTS_LOCAL: + _Thread_queue_Process_timeout( the_thread ); + _Thread_Unnest_dispatch(); + break; + } +} diff --git a/cpukit/score/src/coresem.c b/cpukit/score/src/coresem.c new file mode 100644 index 0000000000..4f5e0720cb --- /dev/null +++ b/cpukit/score/src/coresem.c @@ -0,0 +1,63 @@ +/* + * CORE Semaphore Handler + * + * DESCRIPTION: + * + * This package is the implementation of the CORE Semaphore Handler. + * This core object utilizes standard Dijkstra counting semaphores to provide + * synchronization and mutual exclusion capabilities. + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/coresem.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> + +/*PAGE + * + * CORE_semaphore_Initialize + * + * This function initialize a semaphore and sets the initial value based + * on the given count. + * + * Input parameters: + * the_semaphore - the semaphore control block to initialize + * the_semaphore_attributes - the attributes specified at create time + * initial_value - semaphore's initial value + * + * Output parameters: NONE + */ + +void _CORE_semaphore_Initialize( + CORE_semaphore_Control *the_semaphore, + CORE_semaphore_Attributes *the_semaphore_attributes, + uint32_t initial_value +) +{ + + the_semaphore->Attributes = *the_semaphore_attributes; + the_semaphore->count = initial_value; + + _Thread_queue_Initialize( + &the_semaphore->Wait_queue, + _CORE_semaphore_Is_priority( the_semaphore_attributes ) ? + THREAD_QUEUE_DISCIPLINE_PRIORITY : THREAD_QUEUE_DISCIPLINE_FIFO, + STATES_WAITING_FOR_SEMAPHORE, + CORE_SEMAPHORE_TIMEOUT + ); +} diff --git a/cpukit/score/src/coresemflush.c b/cpukit/score/src/coresemflush.c new file mode 100644 index 0000000000..d4ec72cf22 --- /dev/null +++ b/cpukit/score/src/coresemflush.c @@ -0,0 +1,58 @@ +/* + * CORE Semaphore Handler + * + * DESCRIPTION: + * + * This package is the implementation of the CORE Semaphore Handler. + * This core object utilizes standard Dijkstra counting semaphores to provide + * synchronization and mutual exclusion capabilities. + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/coresem.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> + +/*PAGE + * + * _CORE_semaphore_Flush + * + * This function a flushes the semaphore's task wait queue. + * + * Input parameters: + * the_semaphore - the semaphore to be flushed + * remote_extract_callout - function to invoke remotely + * status - status to pass to thread + * + * Output parameters: NONE + */ + +void _CORE_semaphore_Flush( + CORE_semaphore_Control *the_semaphore, + Thread_queue_Flush_callout remote_extract_callout, + uint32_t status +) +{ + + _Thread_queue_Flush( + &the_semaphore->Wait_queue, + remote_extract_callout, + status + ); + +} diff --git a/cpukit/score/src/coresemseize.c b/cpukit/score/src/coresemseize.c new file mode 100644 index 0000000000..a66690e148 --- /dev/null +++ b/cpukit/score/src/coresemseize.c @@ -0,0 +1,88 @@ +/* + * CORE Semaphore Handler + * + * DESCRIPTION: + * + * This package is the implementation of the CORE Semaphore Handler. + * This core object utilizes standard Dijkstra counting semaphores to provide + * synchronization and mutual exclusion capabilities. + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/coresem.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> + +#if defined(RTEMS_SCORE_CORESEM_ENABLE_SEIZE_BODY) +/* + * This routine attempts to allocate a core semaphore to the calling thread. + * + * Input parameters: + * the_semaphore - pointer to semaphore control block + * id - id of object to wait on + * wait - true if wait is allowed, false otherwise + * timeout - number of ticks to wait (0 means forever) + * + * Output parameters: NONE + * + * INTERRUPT LATENCY: + * available + * wait + */ + +void _CORE_semaphore_Seize( + CORE_semaphore_Control *the_semaphore, + Objects_Id id, + bool wait, + Watchdog_Interval timeout +) +{ + Thread_Control *executing; + ISR_Level level; + + executing = _Thread_Executing; + executing->Wait.return_code = CORE_SEMAPHORE_STATUS_SUCCESSFUL; + _ISR_Disable( level ); + if ( the_semaphore->count != 0 ) { + the_semaphore->count -= 1; + _ISR_Enable( level ); + return; + } + + /* + * If the semaphore was not available and the caller was not willing + * to block, then return immediately with a status indicating that + * the semaphore was not available and the caller never blocked. + */ + if ( !wait ) { + _ISR_Enable( level ); + executing->Wait.return_code = CORE_SEMAPHORE_STATUS_UNSATISFIED_NOWAIT; + return; + } + + /* + * If the semaphore is not available and the caller is willing to + * block, then we now block the caller with optional timeout. + */ + _Thread_queue_Enter_critical_section( &the_semaphore->Wait_queue ); + executing->Wait.queue = &the_semaphore->Wait_queue; + executing->Wait.id = id; + _ISR_Enable( level ); + _Thread_queue_Enqueue( &the_semaphore->Wait_queue, timeout ); +} +#endif diff --git a/cpukit/score/src/coresemsurrender.c b/cpukit/score/src/coresemsurrender.c new file mode 100644 index 0000000000..321d55e198 --- /dev/null +++ b/cpukit/score/src/coresemsurrender.c @@ -0,0 +1,76 @@ +/* + * CORE Semaphore Handler + * + * DESCRIPTION: + * + * This package is the implementation of the CORE Semaphore Handler. + * This core object utilizes standard Dijkstra counting semaphores to provide + * synchronization and mutual exclusion capabilities. + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/coresem.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> + +/*PAGE + * + * _CORE_semaphore_Surrender + * + * Input parameters: + * the_semaphore - the semaphore to be flushed + * id - id of parent semaphore + * api_semaphore_mp_support - api dependent MP support actions + * + * Output parameters: + * CORE_SEMAPHORE_STATUS_SUCCESSFUL - if successful + * core error code - if unsuccessful + * + * Output parameters: + */ + +CORE_semaphore_Status _CORE_semaphore_Surrender( + CORE_semaphore_Control *the_semaphore, + Objects_Id id, + CORE_semaphore_API_mp_support_callout api_semaphore_mp_support +) +{ + Thread_Control *the_thread; + ISR_Level level; + CORE_semaphore_Status status; + + status = CORE_SEMAPHORE_STATUS_SUCCESSFUL; + + if ( (the_thread = _Thread_queue_Dequeue(&the_semaphore->Wait_queue)) ) { + +#if defined(RTEMS_MULTIPROCESSING) + if ( !_Objects_Is_local_id( the_thread->Object.id ) ) + (*api_semaphore_mp_support) ( the_thread, id ); +#endif + + } else { + _ISR_Disable( level ); + if ( the_semaphore->count < the_semaphore->Attributes.maximum_count ) + the_semaphore->count += 1; + else + status = CORE_SEMAPHORE_MAXIMUM_COUNT_EXCEEDED; + _ISR_Enable( level ); + } + + return status; +} diff --git a/cpukit/score/src/corespinlock.c b/cpukit/score/src/corespinlock.c new file mode 100644 index 0000000000..5eb3d327c3 --- /dev/null +++ b/cpukit/score/src/corespinlock.c @@ -0,0 +1,53 @@ +/* + * SuperCore Spinlock Handler + * + * DESCRIPTION: + * + * This package is part of the implementation of the SuperCore Spinlock Handler. + * + * COPYRIGHT (c) 1989-2006. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/corespinlock.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> + +/*PAGE + * + * _CORE_spinlock_Initialize + * + * This function initialize a spinlock and sets the initial value based + * on the given count. + * + * Input parameters: + * the_spinlock - the spinlock control block to initialize + * the_spinlock_attributes - the attributes specified at create time + * + * Output parameters: NONE + */ + +void _CORE_spinlock_Initialize( + CORE_spinlock_Control *the_spinlock, + CORE_spinlock_Attributes *the_spinlock_attributes +) +{ + + the_spinlock->Attributes = *the_spinlock_attributes; + + the_spinlock->lock = 0; + the_spinlock->users = 0; + the_spinlock->holder = 0; +} diff --git a/cpukit/score/src/corespinlockrelease.c b/cpukit/score/src/corespinlockrelease.c new file mode 100644 index 0000000000..fe027448c1 --- /dev/null +++ b/cpukit/score/src/corespinlockrelease.c @@ -0,0 +1,72 @@ +/* + * SuperCore Spinlock Handler -- Release a Spinlock + * + * COPYRIGHT (c) 1989-2006. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/corespinlock.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/watchdog.h> + +/*PAGE + * + * _CORE_spinlock_Release + * + * This function releases the spinlock. + * + * Input parameters: + * the_spinlock - the spinlock control block to initialize + * + * Output parameters: + * CORE_SPINLOCK_SUCCESSFUL - if successful + * error code - if unsuccessful + * + */ + +CORE_spinlock_Status _CORE_spinlock_Release( + CORE_spinlock_Control *the_spinlock +) +{ + ISR_Level level; + + _ISR_Disable( level ); + + /* + * It must locked before it can be unlocked. + */ + if ( the_spinlock->lock == CORE_SPINLOCK_UNLOCKED ) { + _ISR_Enable( level ); + return CORE_SPINLOCK_NOT_LOCKED; + } + + /* + * It must locked by the current thread before it can be unlocked. + */ + if ( the_spinlock->holder != _Thread_Executing->Object.id ) { + _ISR_Enable( level ); + return CORE_SPINLOCK_NOT_HOLDER; + } + + /* + * Let it be unlocked. + */ + the_spinlock->users -= 1; + the_spinlock->lock = CORE_SPINLOCK_UNLOCKED; + the_spinlock->holder = 0; + + _ISR_Enable( level ); + return CORE_SPINLOCK_SUCCESSFUL; +} diff --git a/cpukit/score/src/corespinlockwait.c b/cpukit/score/src/corespinlockwait.c new file mode 100644 index 0000000000..cf15163977 --- /dev/null +++ b/cpukit/score/src/corespinlockwait.c @@ -0,0 +1,114 @@ +/* + * SuperCore Spinlock Handler -- Wait for Spinlock + * + * COPYRIGHT (c) 1989-2009. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/corespinlock.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/watchdog.h> + +/*PAGE + * + * _CORE_spinlock_Wait + * + * This function waits for the spinlock to become available. Optionally, + * a limit may be placed on the duration of the spin. + * + * Input parameters: + * the_spinlock - the spinlock control block to initialize + * wait - true if willing to wait + * timeout - the maximum number of ticks to spin (0 is forever) + * + * Output parameters: NONE + */ + +CORE_spinlock_Status _CORE_spinlock_Wait( + CORE_spinlock_Control *the_spinlock, + bool wait, + Watchdog_Interval timeout +) +{ + ISR_Level level; + #if defined(FUNCTIONALITY_NOT_CURRENTLY_USED_BY_ANY_API) + Watchdog_Interval limit = _Watchdog_Ticks_since_boot + timeout; + #endif + + _ISR_Disable( level ); + if ( (the_spinlock->lock == CORE_SPINLOCK_LOCKED) && + (the_spinlock->holder == _Thread_Executing->Object.id) ) { + _ISR_Enable( level ); + return CORE_SPINLOCK_HOLDER_RELOCKING; + } + the_spinlock->users += 1; + for ( ;; ) { + if ( the_spinlock->lock == CORE_SPINLOCK_UNLOCKED ) { + the_spinlock->lock = CORE_SPINLOCK_LOCKED; + the_spinlock->holder = _Thread_Executing->Object.id; + _ISR_Enable( level ); + return CORE_SPINLOCK_SUCCESSFUL; + } + + /* + * Spinlock is unavailable. If not willing to wait, return. + */ + if ( !wait ) { + the_spinlock->users -= 1; + _ISR_Enable( level ); + return CORE_SPINLOCK_UNAVAILABLE; + } + + #if defined(FUNCTIONALITY_NOT_CURRENTLY_USED_BY_ANY_API) + /* + * They are willing to wait but there could be a timeout. + */ + if ( timeout && (limit <= _Watchdog_Ticks_since_boot) ) { + the_spinlock->users -= 1; + _ISR_Enable( level ); + return CORE_SPINLOCK_TIMEOUT; + } + #endif + + /* + * The thread is willing to spin so let's set things up so + * another thread has a chance of running. This spinlock has + * to be released by either another thread or an ISR. Since + * POSIX does not say anything about ISRs, that implies that + * another thread must be able to run while spinning. We are + * not blocking so that implies we are at least preemptible + * and possibly time-sliced. + * + * So first, we will enable interrpts to allow for them to happen. + * Then we will "flash" the thread dispatching critical section + * so other threads have a chance to run. + * + * A spinlock cannot be deleted while it is being used so we are + * safe from deletion. + */ + + _ISR_Enable( level ); + /* An ISR could occur here */ + + _Thread_Enable_dispatch(); + /* Another thread could get dispatched here */ + + /* Reenter the critical sections so we can attempt the lock again. */ + _Thread_Disable_dispatch(); + + _ISR_Disable( level ); + } + +} diff --git a/cpukit/score/src/coretod.c b/cpukit/score/src/coretod.c new file mode 100644 index 0000000000..4da8dd4b4f --- /dev/null +++ b/cpukit/score/src/coretod.c @@ -0,0 +1,47 @@ +/* + * Time of Day (TOD) Handler + */ + +/* COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#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_Handler_initialization + * + * This routine initializes the time of day handler. + * + * Input parameters: NONE + * + * Output parameters: NONE + */ + +void _TOD_Handler_initialization(void) +{ + /* POSIX format TOD (timespec) */ + _Timestamp_Set( &_TOD_Now, TOD_SECONDS_1970_THROUGH_1988, 0 ); + + /* Uptime (timespec) */ + _Timestamp_Set_to_zero( &_TOD_Uptime ); + + /* TOD has not been set */ + _TOD_Is_set = false; + _TOD_Activate(); +} diff --git a/cpukit/score/src/coretodget.c b/cpukit/score/src/coretodget.c new file mode 100644 index 0000000000..953f3cb753 --- /dev/null +++ b/cpukit/score/src/coretodget.c @@ -0,0 +1,56 @@ +/* + * Time of Day (TOD) Handler - get TOD + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/timespec.h> +#include <rtems/score/timestamp.h> +#include <rtems/score/tod.h> +#include <rtems/score/watchdog.h> + +/* + * _TOD_Get + * + * This routine is used to obtain the current date and time. + * + * Input parameters: + * time - pointer to the time and date structure + * + * Output parameters: NONE + */ + +void _TOD_Get( + struct timespec *time +) +{ + ISR_Level level; + Timestamp_Control offset; + Timestamp_Control now; + long nanoseconds; + + /* assume time checked for NULL by caller */ + + /* _TOD_Now is the native current time */ + _ISR_Disable( level ); + now = _TOD_Now; + nanoseconds = (*_Watchdog_Nanoseconds_since_tick_handler)(); + _ISR_Enable( level ); + + _Timestamp_Set( &offset, 0, nanoseconds ); + _Timestamp_Add_to( &now, &offset ); + _Timestamp_To_timespec( &now, time ); +} diff --git a/cpukit/score/src/coretodgetuptime.c b/cpukit/score/src/coretodgetuptime.c new file mode 100644 index 0000000000..c5d940b0c0 --- /dev/null +++ b/cpukit/score/src/coretodgetuptime.c @@ -0,0 +1,56 @@ +/* + * Time of Day (TOD) Handler - get uptime + */ + +/* COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/timestamp.h> +#include <rtems/score/tod.h> +#include <rtems/score/watchdog.h> + +/* + * _TOD_Get_uptime + * + * This routine is used to obtain the system uptime + * + * Input parameters: + * time - pointer to the timestamp structure + * + * Output parameters: NONE + */ + +void _TOD_Get_uptime( + Timestamp_Control *uptime +) +{ + ISR_Level level; + Timestamp_Control offset; + Timestamp_Control up; + long nanoseconds; + + /* assume time checked for NULL by caller */ + + /* _TOD_Uptime is in native timestamp format */ + _ISR_Disable( level ); + up = _TOD_Uptime; + nanoseconds = (*_Watchdog_Nanoseconds_since_tick_handler)(); + _ISR_Enable( level ); + + _Timestamp_Set( &offset, 0, nanoseconds ); + _Timestamp_Add_to( &up, &offset ); + *uptime = up; +} diff --git a/cpukit/score/src/coretodgetuptimetimespec.c b/cpukit/score/src/coretodgetuptimetimespec.c new file mode 100644 index 0000000000..6d30a95d9c --- /dev/null +++ b/cpukit/score/src/coretodgetuptimetimespec.c @@ -0,0 +1,44 @@ +/* + * Time of Day (TOD) Handler - get uptime + */ + +/* COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/timestamp.h> +#include <rtems/score/tod.h> + +/* + * _TOD_Get_uptime_as_timespec + * + * This routine is used to obtain the system uptime + * + * Input parameters: + * time - pointer to the timestamp structure + * + * Output parameters: NONE + */ + +void _TOD_Get_uptime_as_timespec( + struct timespec *uptime +) +{ + Timestamp_Control uptime_ts; + + /* assume time checked for NULL by caller */ + _TOD_Get_uptime( &uptime_ts ); + _Timestamp_To_timespec( &uptime_ts, uptime ); +} diff --git a/cpukit/score/src/coretodmsecstoticks.c b/cpukit/score/src/coretodmsecstoticks.c new file mode 100644 index 0000000000..cddd3d646d --- /dev/null +++ b/cpukit/score/src/coretodmsecstoticks.c @@ -0,0 +1,25 @@ +/* COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/config.h> +#include <rtems/score/tod.h> + +uint32_t TOD_MILLISECONDS_TO_TICKS( + uint32_t milliseconds +) +{ + return (milliseconds / rtems_configuration_get_milliseconds_per_tick()); +} diff --git a/cpukit/score/src/coretodset.c b/cpukit/score/src/coretodset.c new file mode 100644 index 0000000000..9329fd7d8f --- /dev/null +++ b/cpukit/score/src/coretodset.c @@ -0,0 +1,62 @@ +/* + * Time of Day (TOD) Handler -- Set Time + */ + +/* COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/score/thread.h> +#include <rtems/score/timestamp.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: + * time - pointer to the time and date structure + * + * Output parameters: NONE + */ + +void _TOD_Set( + const struct timespec *time +) +{ + long seconds; + + _Thread_Disable_dispatch(); + _TOD_Deactivate(); + + seconds = _TOD_Seconds_since_epoch(); + + if ( time->tv_sec < seconds ) + _Watchdog_Adjust_seconds( WATCHDOG_BACKWARD, seconds - time->tv_sec ); + else + _Watchdog_Adjust_seconds( WATCHDOG_FORWARD, time->tv_sec - seconds ); + + /* POSIX format TOD (timespec) */ + _Timestamp_Set( &_TOD_Now, time->tv_sec, time->tv_nsec ); + _TOD_Is_set = true; + + _TOD_Activate(); + + _Thread_Enable_dispatch(); +} diff --git a/cpukit/score/src/coretodtickle.c b/cpukit/score/src/coretodtickle.c new file mode 100644 index 0000000000..ddc8e4aac0 --- /dev/null +++ b/cpukit/score/src/coretodtickle.c @@ -0,0 +1,60 @@ +/* + * Time of Day (TOD) Handler -- Tickle Ticks + */ + +/* COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/score/thread.h> +#include <rtems/score/timestamp.h> +#include <rtems/score/tod.h> +#include <rtems/score/watchdog.h> +#include <rtems/config.h> + +/*PAGE + * + * _TOD_Tickle_ticks + * + * This routine processes a clock tick. + * + * Input parameters: NONE + * + * Output parameters: NONE + */ + +void _TOD_Tickle_ticks( void ) +{ + Timestamp_Control tick; + uint32_t seconds; + + /* Convert the tick quantum to a timestamp */ + _Timestamp_Set( &tick, 0, rtems_configuration_get_nanoseconds_per_tick() ); + + /* Update the counter of ticks since boot */ + _Watchdog_Ticks_since_boot += 1; + + /* Update the timespec format uptime */ + _Timestamp_Add_to( &_TOD_Uptime, &tick ); + /* we do not care how much the uptime changed */ + + /* Update the timespec format TOD */ + seconds = _Timestamp_Add_to_at_tick( &_TOD_Now, &tick ); + while ( seconds ) { + _Watchdog_Tickle_seconds(); + seconds--; + } +} + diff --git a/cpukit/score/src/coretodtickspersec.c b/cpukit/score/src/coretodtickspersec.c new file mode 100644 index 0000000000..ac6316ba7b --- /dev/null +++ b/cpukit/score/src/coretodtickspersec.c @@ -0,0 +1,24 @@ +/* COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/config.h> +#include <rtems/score/tod.h> + +uint32_t TOD_TICKS_PER_SECOND_method(void) +{ + return (TOD_MICROSECONDS_PER_SECOND / + rtems_configuration_get_microseconds_per_tick()); +} diff --git a/cpukit/score/src/coretodusectoticks.c b/cpukit/score/src/coretodusectoticks.c new file mode 100644 index 0000000000..be2cbd7024 --- /dev/null +++ b/cpukit/score/src/coretodusectoticks.c @@ -0,0 +1,25 @@ +/* COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/config.h> +#include <rtems/score/tod.h> + +uint32_t TOD_MICROSECONDS_TO_TICKS( + uint32_t microseconds +) +{ + return (microseconds / rtems_configuration_get_microseconds_per_tick()); +} diff --git a/cpukit/score/src/heap.c b/cpukit/score/src/heap.c new file mode 100644 index 0000000000..b972d84c3c --- /dev/null +++ b/cpukit/score/src/heap.c @@ -0,0 +1,488 @@ +/** + * @file + * + * @ingroup ScoreHeap + * + * @brief Heap Handler implementation. + */ + +/* + * COPYRIGHT (c) 1989-2009. + * On-Line Applications Research Corporation (OAR). + * + * Copyright (c) 2009, 2010 embedded brains GmbH. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> + +#include <rtems/system.h> +#include <rtems/score/heap.h> +#include <rtems/score/interr.h> + +#if CPU_ALIGNMENT == 0 || CPU_ALIGNMENT % 2 != 0 + #error "invalid CPU_ALIGNMENT value" +#endif + +static uint32_t instance = 0; + +/*PAGE + * + * _Heap_Initialize + * + * This kernel routine initializes a heap. + * + * Input parameters: + * heap - pointer to heap header + * area_begin - starting address of heap + * size - size of heap + * page_size - allocatable unit of memory + * + * Output parameters: + * returns - maximum memory available if RTEMS_SUCCESSFUL + * 0 - otherwise + * + * This is what a heap looks like in memory immediately after initialization: + * + * + * +--------------------------------+ <- begin = area_begin + * | unused space due to alignment | + * | size < page_size | + * 0 +--------------------------------+ <- first block + * | prev_size = page_size | + * 4 +--------------------------------+ + * | size = size0 | 1 | + * 8 +---------------------+----------+ <- aligned on page_size + * | next = HEAP_TAIL | | + * 12 +---------------------+ | + * | prev = HEAP_HEAD | memory | + * +---------------------+ | + * | available | + * | | + * | for allocation | + * | | + * size0 +--------------------------------+ <- last dummy block + * | prev_size = size0 | + * +4 +--------------------------------+ + * | size = page_size | 0 | <- prev block is free + * +8 +--------------------------------+ <- aligned on page_size + * | unused space due to alignment | + * | size < page_size | + * +--------------------------------+ <- end = begin + size + * + * Below is what a heap looks like after first allocation of SIZE bytes using + * _Heap_allocate(). BSIZE stands for SIZE + 4 aligned up on 'page_size' + * boundary. + * [NOTE: If allocation were performed by _Heap_Allocate_aligned(), the + * block size BSIZE is defined differently, and previously free block will + * be split so that upper part of it will become used block (see + * 'heapallocatealigned.c' for details).] + * + * +--------------------------------+ <- begin = area_begin + * | unused space due to alignment | + * | size < page_size | + * 0 +--------------------------------+ <- used block + * | prev_size = page_size | + * 4 +--------------------------------+ + * | size = BSIZE | 1 | <- prev block is used + * 8 +--------------------------------+ <- aligned on page_size + * | . | Pointer returned to the user + * | . | is 8 for _Heap_Allocate() + * | . | and is in range + * 8 + | user-accessible | [8,8+page_size) for + * page_size +- - - - - -+ _Heap_Allocate_aligned() + * | area | + * | . | + * BSIZE +- - - - - . - - - - -+ <- free block + * | . | + * BSIZE +4 +--------------------------------+ + * | size = S = size0 - BSIZE | 1 | <- prev block is used + * BSIZE +8 +-------------------+------------+ <- aligned on page_size + * | next = HEAP_TAIL | | + * BSIZE +12 +-------------------+ | + * | prev = HEAP_HEAD | memory | + * +-------------------+ | + * | . available | + * | . | + * | . for | + * | . | + * BSIZE +S+0 +-------------------+ allocation + <- last dummy block + * | prev_size = S | | + * +S+4 +-------------------+------------+ + * | size = page_size | 0 | <- prev block is free + * +S+8 +--------------------------------+ <- aligned on page_size + * | unused space due to alignment | + * | size < page_size | + * +--------------------------------+ <- end = begin + size + * + */ + +#ifdef HEAP_PROTECTION + static void _Heap_Protection_block_initialize_default( + Heap_Control *heap, + Heap_Block *block + ) + { + block->Protection_begin.protector [0] = HEAP_BEGIN_PROTECTOR_0; + block->Protection_begin.protector [1] = HEAP_BEGIN_PROTECTOR_1; + block->Protection_begin.next_delayed_free_block = NULL; + block->Protection_begin.task = _Thread_Executing; + block->Protection_begin.tag = NULL; + block->Protection_end.protector [0] = HEAP_END_PROTECTOR_0; + block->Protection_end.protector [1] = HEAP_END_PROTECTOR_1; + } + + static void _Heap_Protection_block_check_default( + Heap_Control *heap, + Heap_Block *block + ) + { + if ( + block->Protection_begin.protector [0] != HEAP_BEGIN_PROTECTOR_0 + || block->Protection_begin.protector [1] != HEAP_BEGIN_PROTECTOR_1 + || block->Protection_end.protector [0] != HEAP_END_PROTECTOR_0 + || block->Protection_end.protector [1] != HEAP_END_PROTECTOR_1 + ) { + _Heap_Protection_block_error( heap, block ); + } + } + + static void _Heap_Protection_block_error_default( + Heap_Control *heap, + Heap_Block *block + ) + { + /* FIXME */ + _Internal_error_Occurred( 0xdeadbeef, false, 0xdeadbeef ); + } +#endif + +bool _Heap_Get_first_and_last_block( + uintptr_t heap_area_begin, + uintptr_t heap_area_size, + uintptr_t page_size, + uintptr_t min_block_size, + Heap_Block **first_block_ptr, + Heap_Block **last_block_ptr +) +{ + uintptr_t const heap_area_end = heap_area_begin + heap_area_size; + uintptr_t const alloc_area_begin = + _Heap_Align_up( heap_area_begin + HEAP_BLOCK_HEADER_SIZE, page_size ); + uintptr_t const first_block_begin = + alloc_area_begin - HEAP_BLOCK_HEADER_SIZE; + uintptr_t const overhead = + HEAP_BLOCK_HEADER_SIZE + (first_block_begin - heap_area_begin); + uintptr_t const first_block_size = + _Heap_Align_down( heap_area_size - overhead, page_size ); + Heap_Block *const first_block = (Heap_Block *) first_block_begin; + Heap_Block *const last_block = + _Heap_Block_at( first_block, first_block_size ); + + if ( + heap_area_end < heap_area_begin + || heap_area_size <= overhead + || first_block_size < min_block_size + ) { + /* Invalid area or area too small */ + return false; + } + + *first_block_ptr = first_block; + *last_block_ptr = last_block; + + return true; +} + +uintptr_t _Heap_Initialize( + Heap_Control *heap, + void *heap_area_begin_ptr, + uintptr_t heap_area_size, + uintptr_t page_size +) +{ + Heap_Statistics *const stats = &heap->stats; + uintptr_t const heap_area_begin = (uintptr_t) heap_area_begin_ptr; + uintptr_t const heap_area_end = heap_area_begin + heap_area_size; + uintptr_t first_block_begin = 0; + uintptr_t first_block_size = 0; + uintptr_t last_block_begin = 0; + uintptr_t min_block_size = 0; + bool area_ok = false; + Heap_Block *first_block = NULL; + Heap_Block *last_block = NULL; + + if ( page_size == 0 ) { + page_size = CPU_ALIGNMENT; + } else { + page_size = _Heap_Align_up( page_size, CPU_ALIGNMENT ); + + if ( page_size < CPU_ALIGNMENT ) { + /* Integer overflow */ + return 0; + } + } + min_block_size = _Heap_Align_up( sizeof( Heap_Block ), page_size ); + + area_ok = _Heap_Get_first_and_last_block( + heap_area_begin, + heap_area_size, + page_size, + min_block_size, + &first_block, + &last_block + ); + if ( !area_ok ) { + return 0; + } + + memset(heap, 0, sizeof(*heap)); + + #ifdef HEAP_PROTECTION + heap->Protection.block_initialize = _Heap_Protection_block_initialize_default; + heap->Protection.block_check = _Heap_Protection_block_check_default; + heap->Protection.block_error = _Heap_Protection_block_error_default; + #endif + + first_block_begin = (uintptr_t) first_block; + last_block_begin = (uintptr_t) last_block; + first_block_size = last_block_begin - first_block_begin; + + /* First block */ + first_block->prev_size = heap_area_end; + first_block->size_and_flag = first_block_size | HEAP_PREV_BLOCK_USED; + first_block->next = _Heap_Free_list_tail( heap ); + first_block->prev = _Heap_Free_list_head( heap ); + _Heap_Protection_block_initialize( heap, first_block ); + + /* Heap control */ + heap->page_size = page_size; + heap->min_block_size = min_block_size; + heap->area_begin = heap_area_begin; + heap->area_end = heap_area_end; + heap->first_block = first_block; + heap->last_block = last_block; + _Heap_Free_list_head( heap )->next = first_block; + _Heap_Free_list_tail( heap )->prev = first_block; + + /* Last block */ + last_block->prev_size = first_block_size; + last_block->size_and_flag = 0; + _Heap_Set_last_block_size( heap ); + _Heap_Protection_block_initialize( heap, last_block ); + + /* Statistics */ + stats->size = first_block_size; + stats->free_size = first_block_size; + stats->min_free_size = first_block_size; + stats->free_blocks = 1; + stats->max_free_blocks = 1; + stats->instance = instance++; + + _HAssert( _Heap_Is_aligned( heap->page_size, CPU_ALIGNMENT ) ); + _HAssert( _Heap_Is_aligned( heap->min_block_size, page_size ) ); + _HAssert( + _Heap_Is_aligned( _Heap_Alloc_area_of_block( first_block ), page_size ) + ); + _HAssert( + _Heap_Is_aligned( _Heap_Alloc_area_of_block( last_block ), page_size ) + ); + + return first_block_size; +} + +static void _Heap_Block_split( + Heap_Control *heap, + Heap_Block *block, + Heap_Block *free_list_anchor, + uintptr_t alloc_size +) +{ + Heap_Statistics *const stats = &heap->stats; + + uintptr_t const page_size = heap->page_size; + uintptr_t const min_block_size = heap->min_block_size; + uintptr_t const min_alloc_size = min_block_size - HEAP_BLOCK_HEADER_SIZE; + + uintptr_t const block_size = _Heap_Block_size( block ); + + uintptr_t const used_size = + _Heap_Max( alloc_size, min_alloc_size ) + HEAP_BLOCK_HEADER_SIZE; + uintptr_t const used_block_size = _Heap_Align_up( used_size, page_size ); + + uintptr_t const free_size = block_size + HEAP_ALLOC_BONUS - used_size; + uintptr_t const free_size_limit = min_block_size + HEAP_ALLOC_BONUS; + + Heap_Block *next_block = _Heap_Block_at( block, block_size ); + + _HAssert( used_size <= block_size + HEAP_ALLOC_BONUS ); + _HAssert( used_size + free_size == block_size + HEAP_ALLOC_BONUS ); + + if ( free_size >= free_size_limit ) { + Heap_Block *const free_block = _Heap_Block_at( block, used_block_size ); + uintptr_t free_block_size = block_size - used_block_size; + + _HAssert( used_block_size + free_block_size == block_size ); + + _Heap_Block_set_size( block, used_block_size ); + + /* Statistics */ + stats->free_size += free_block_size; + + if ( _Heap_Is_used( next_block ) ) { + _Heap_Free_list_insert_after( free_list_anchor, free_block ); + + /* Statistics */ + ++stats->free_blocks; + } else { + uintptr_t const next_block_size = _Heap_Block_size( next_block ); + + _Heap_Free_list_replace( next_block, free_block ); + + free_block_size += next_block_size; + + next_block = _Heap_Block_at( free_block, free_block_size ); + } + + free_block->size_and_flag = free_block_size | HEAP_PREV_BLOCK_USED; + + next_block->prev_size = free_block_size; + next_block->size_and_flag &= ~HEAP_PREV_BLOCK_USED; + + _Heap_Protection_block_initialize( heap, free_block ); + } else { + next_block->size_and_flag |= HEAP_PREV_BLOCK_USED; + } +} + +static Heap_Block *_Heap_Block_allocate_from_begin( + Heap_Control *heap, + Heap_Block *block, + Heap_Block *free_list_anchor, + uintptr_t alloc_size +) +{ + _Heap_Block_split( heap, block, free_list_anchor, alloc_size ); + + return block; +} + +static Heap_Block *_Heap_Block_allocate_from_end( + Heap_Control *heap, + Heap_Block *block, + Heap_Block *free_list_anchor, + uintptr_t alloc_begin, + uintptr_t alloc_size +) +{ + Heap_Statistics *const stats = &heap->stats; + + uintptr_t block_begin = (uintptr_t) block; + uintptr_t block_size = _Heap_Block_size( block ); + uintptr_t block_end = block_begin + block_size; + + Heap_Block *const new_block = + _Heap_Block_of_alloc_area( alloc_begin, heap->page_size ); + uintptr_t const new_block_begin = (uintptr_t) new_block; + uintptr_t const new_block_size = block_end - new_block_begin; + + block_end = new_block_begin; + block_size = block_end - block_begin; + + _HAssert( block_size >= heap->min_block_size ); + _HAssert( new_block_size >= heap->min_block_size ); + + /* Statistics */ + stats->free_size += block_size; + + if ( _Heap_Is_prev_used( block ) ) { + _Heap_Free_list_insert_after( free_list_anchor, block ); + + free_list_anchor = block; + + /* Statistics */ + ++stats->free_blocks; + } else { + Heap_Block *const prev_block = _Heap_Prev_block( block ); + uintptr_t const prev_block_size = _Heap_Block_size( prev_block ); + + block = prev_block; + block_size += prev_block_size; + } + + block->size_and_flag = block_size | HEAP_PREV_BLOCK_USED; + + new_block->prev_size = block_size; + new_block->size_and_flag = new_block_size; + + _Heap_Block_split( heap, new_block, free_list_anchor, alloc_size ); + + return new_block; +} + +Heap_Block *_Heap_Block_allocate( + Heap_Control *heap, + Heap_Block *block, + uintptr_t alloc_begin, + uintptr_t alloc_size +) +{ + Heap_Statistics *const stats = &heap->stats; + + uintptr_t const alloc_area_begin = _Heap_Alloc_area_of_block( block ); + uintptr_t const alloc_area_offset = alloc_begin - alloc_area_begin; + + Heap_Block *free_list_anchor = NULL; + + _HAssert( alloc_area_begin <= alloc_begin ); + + if ( _Heap_Is_free( block ) ) { + free_list_anchor = block->prev; + + _Heap_Free_list_remove( block ); + + /* Statistics */ + --stats->free_blocks; + ++stats->used_blocks; + stats->free_size -= _Heap_Block_size( block ); + } else { + free_list_anchor = _Heap_Free_list_head( heap ); + } + + if ( alloc_area_offset < heap->page_size ) { + alloc_size += alloc_area_offset; + + block = _Heap_Block_allocate_from_begin( + heap, + block, + free_list_anchor, + alloc_size + ); + } else { + block = _Heap_Block_allocate_from_end( + heap, + block, + free_list_anchor, + alloc_begin, + alloc_size + ); + } + + /* Statistics */ + if ( stats->min_free_size > stats->free_size ) { + stats->min_free_size = stats->free_size; + } + + _Heap_Protection_block_initialize( heap, block ); + + return block; +} diff --git a/cpukit/score/src/heapallocate.c b/cpukit/score/src/heapallocate.c new file mode 100644 index 0000000000..61cebc2054 --- /dev/null +++ b/cpukit/score/src/heapallocate.c @@ -0,0 +1,280 @@ +/** + * @file + * + * @ingroup ScoreHeap + * + * @brief Heap Handler implementation. + */ + +/* + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * Copyright (c) 2009 embedded brains GmbH. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/heap.h> + +#ifndef HEAP_PROTECTION + #define _Heap_Protection_free_delayed_blocks( heap, alloc_begin ) false +#else + static bool _Heap_Protection_free_delayed_blocks( + Heap_Control *heap, + uintptr_t alloc_begin + ) + { + bool search_again = false; + uintptr_t const blocks_to_free_count = + (heap->Protection.delayed_free_block_count + 1) / 2; + + if ( alloc_begin == 0 && blocks_to_free_count > 0 ) { + Heap_Block *block_to_free = heap->Protection.first_delayed_free_block; + uintptr_t count = 0; + + for ( count = 0; count < blocks_to_free_count; ++count ) { + Heap_Block *next_block_to_free = + block_to_free->Protection_begin.next_delayed_free_block; + + block_to_free->Protection_begin.next_delayed_free_block = + HEAP_PROTECTION_OBOLUS; + + _Heap_Free( + heap, + (void *) _Heap_Alloc_area_of_block( block_to_free ) + ); + + block_to_free = next_block_to_free; + } + + heap->Protection.delayed_free_block_count -= blocks_to_free_count; + heap->Protection.first_delayed_free_block = block_to_free; + + search_again = true; + } + + return search_again; + } +#endif + +#ifdef RTEMS_HEAP_DEBUG + static void _Heap_Check_allocation( + const Heap_Control *heap, + const Heap_Block *block, + uintptr_t alloc_begin, + uintptr_t alloc_size, + uintptr_t alignment, + uintptr_t boundary + ) + { + uintptr_t const min_block_size = heap->min_block_size; + uintptr_t const page_size = heap->page_size; + + uintptr_t const block_begin = (uintptr_t) block; + uintptr_t const block_size = _Heap_Block_size( block ); + uintptr_t const block_end = block_begin + block_size; + + uintptr_t const alloc_end = alloc_begin + alloc_size; + + uintptr_t const alloc_area_begin = _Heap_Alloc_area_of_block( block ); + uintptr_t const alloc_area_offset = alloc_begin - alloc_area_begin; + + _HAssert( block_size >= min_block_size ); + _HAssert( block_begin < block_end ); + _HAssert( + _Heap_Is_aligned( block_begin + HEAP_BLOCK_HEADER_SIZE, page_size ) + ); + _HAssert( + _Heap_Is_aligned( block_size, page_size ) + ); + + _HAssert( alloc_end <= block_end + HEAP_ALLOC_BONUS ); + _HAssert( alloc_area_begin == block_begin + HEAP_BLOCK_HEADER_SIZE); + _HAssert( alloc_area_offset < page_size ); + + _HAssert( _Heap_Is_aligned( alloc_area_begin, page_size ) ); + if ( alignment == 0 ) { + _HAssert( alloc_begin == alloc_area_begin ); + } else { + _HAssert( _Heap_Is_aligned( alloc_begin, alignment ) ); + } + + if ( boundary != 0 ) { + uintptr_t boundary_line = _Heap_Align_down( alloc_end, boundary ); + + _HAssert( alloc_size <= boundary ); + _HAssert( boundary_line <= alloc_begin || alloc_end <= boundary_line ); + } + } +#else + #define _Heap_Check_allocation( h, b, ab, as, ag, bd ) ((void) 0) +#endif + +static uintptr_t _Heap_Check_block( + const Heap_Control *heap, + const Heap_Block *block, + uintptr_t alloc_size, + uintptr_t alignment, + uintptr_t boundary +) +{ + uintptr_t const page_size = heap->page_size; + uintptr_t const min_block_size = heap->min_block_size; + + uintptr_t const block_begin = (uintptr_t) block; + uintptr_t const block_size = _Heap_Block_size( block ); + uintptr_t const block_end = block_begin + block_size; + + uintptr_t const alloc_begin_floor = _Heap_Alloc_area_of_block( block ); + uintptr_t const alloc_begin_ceiling = block_end - min_block_size + + HEAP_BLOCK_HEADER_SIZE + page_size - 1; + + uintptr_t alloc_end = block_end + HEAP_ALLOC_BONUS; + uintptr_t alloc_begin = alloc_end - alloc_size; + + alloc_begin = _Heap_Align_down( alloc_begin, alignment ); + + /* Ensure that the we have a valid new block at the end */ + if ( alloc_begin > alloc_begin_ceiling ) { + alloc_begin = _Heap_Align_down( alloc_begin_ceiling, alignment ); + } + + alloc_end = alloc_begin + alloc_size; + + /* Ensure boundary constaint */ + if ( boundary != 0 ) { + uintptr_t const boundary_floor = alloc_begin_floor + alloc_size; + uintptr_t boundary_line = _Heap_Align_down( alloc_end, boundary ); + + while ( alloc_begin < boundary_line && boundary_line < alloc_end ) { + if ( boundary_line < boundary_floor ) { + return 0; + } + alloc_begin = boundary_line - alloc_size; + alloc_begin = _Heap_Align_down( alloc_begin, alignment ); + alloc_end = alloc_begin + alloc_size; + boundary_line = _Heap_Align_down( alloc_end, boundary ); + } + } + + /* Ensure that the we have a valid new block at the beginning */ + if ( alloc_begin >= alloc_begin_floor ) { + uintptr_t const alloc_block_begin = + (uintptr_t) _Heap_Block_of_alloc_area( alloc_begin, page_size ); + uintptr_t const free_size = alloc_block_begin - block_begin; + + if ( free_size >= min_block_size || free_size == 0 ) { + return alloc_begin; + } + } + + return 0; +} + +void *_Heap_Allocate_aligned_with_boundary( + Heap_Control *heap, + uintptr_t alloc_size, + uintptr_t alignment, + uintptr_t boundary +) +{ + Heap_Statistics *const stats = &heap->stats; + uintptr_t const block_size_floor = alloc_size + HEAP_BLOCK_HEADER_SIZE + - HEAP_ALLOC_BONUS; + uintptr_t const page_size = heap->page_size; + Heap_Block *block = NULL; + uintptr_t alloc_begin = 0; + uint32_t search_count = 0; + bool search_again = false; + + if ( block_size_floor < alloc_size ) { + /* Integer overflow occured */ + return NULL; + } + + if ( boundary != 0 ) { + if ( boundary < alloc_size ) { + return NULL; + } + + if ( alignment == 0 ) { + alignment = page_size; + } + } + + do { + Heap_Block *const free_list_tail = _Heap_Free_list_tail( heap ); + + block = _Heap_Free_list_first( heap ); + while ( block != free_list_tail ) { + _HAssert( _Heap_Is_prev_used( block ) ); + + _Heap_Protection_block_check( heap, block ); + + /* + * The HEAP_PREV_BLOCK_USED flag is always set in the block size_and_flag + * field. Thus the value is about one unit larger than the real block + * size. The greater than operator takes this into account. + */ + if ( block->size_and_flag > block_size_floor ) { + if ( alignment == 0 ) { + alloc_begin = _Heap_Alloc_area_of_block( block ); + } else { + alloc_begin = _Heap_Check_block( + heap, + block, + alloc_size, + alignment, + boundary + ); + } + } + + /* Statistics */ + ++search_count; + + if ( alloc_begin != 0 ) { + break; + } + + block = block->next; + } + + search_again = _Heap_Protection_free_delayed_blocks( heap, alloc_begin ); + } while ( search_again ); + + if ( alloc_begin != 0 ) { + /* Statistics */ + ++stats->allocs; + stats->searches += search_count; + + block = _Heap_Block_allocate( heap, block, alloc_begin, alloc_size ); + + _Heap_Check_allocation( + heap, + block, + alloc_begin, + alloc_size, + alignment, + boundary + ); + } + + /* Statistics */ + if ( stats->max_search < search_count ) { + stats->max_search = search_count; + } + + return (void *) alloc_begin; +} diff --git a/cpukit/score/src/heapextend.c b/cpukit/score/src/heapextend.c new file mode 100644 index 0000000000..eab2a9482d --- /dev/null +++ b/cpukit/score/src/heapextend.c @@ -0,0 +1,243 @@ +/** + * @file + * + * @ingroup ScoreHeap + * + * @brief Heap Handler implementation. + */ + +/* + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * Copyright (c) 2010 embedded brains GmbH. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/heap.h> + +static void _Heap_Free_block( Heap_Control *heap, Heap_Block *block ) +{ + Heap_Statistics *const stats = &heap->stats; + + /* Statistics */ + ++stats->used_blocks; + --stats->frees; + + _Heap_Free( heap, (void *) _Heap_Alloc_area_of_block( block )); +} + +static void _Heap_Merge_below( + Heap_Control *heap, + uintptr_t extend_area_begin, + Heap_Block *first_block +) +{ + uintptr_t const page_size = heap->page_size; + uintptr_t const new_first_block_alloc_begin = + _Heap_Align_up( extend_area_begin + HEAP_BLOCK_HEADER_SIZE, page_size ); + uintptr_t const new_first_block_begin = + new_first_block_alloc_begin - HEAP_BLOCK_HEADER_SIZE; + uintptr_t const first_block_begin = (uintptr_t) first_block; + uintptr_t const new_first_block_size = + first_block_begin - new_first_block_begin; + Heap_Block *const new_first_block = (Heap_Block *) new_first_block_begin; + + new_first_block->prev_size = first_block->prev_size; + new_first_block->size_and_flag = new_first_block_size | HEAP_PREV_BLOCK_USED; + + _Heap_Free_block( heap, new_first_block ); +} + +static void _Heap_Merge_above( + Heap_Control *heap, + Heap_Block *last_block, + uintptr_t extend_area_end +) +{ + uintptr_t const page_size = heap->page_size; + uintptr_t const last_block_begin = (uintptr_t) last_block; + uintptr_t const last_block_new_size = _Heap_Align_down( + extend_area_end - last_block_begin - HEAP_BLOCK_HEADER_SIZE, + page_size + ); + Heap_Block *const new_last_block = + _Heap_Block_at( last_block, last_block_new_size ); + + new_last_block->size_and_flag = + (last_block->size_and_flag - last_block_new_size) + | HEAP_PREV_BLOCK_USED; + + _Heap_Block_set_size( last_block, last_block_new_size ); + + _Heap_Free_block( heap, last_block ); +} + +static void _Heap_Link_below( + Heap_Block *link, + Heap_Block *last_block +) +{ + uintptr_t const last_block_begin = (uintptr_t) last_block; + uintptr_t const link_begin = (uintptr_t) link; + + last_block->size_and_flag = + (link_begin - last_block_begin) | HEAP_PREV_BLOCK_USED; +} + +static void _Heap_Link_above( + Heap_Block *link, + Heap_Block *first_block, + Heap_Block *last_block +) +{ + uintptr_t const link_begin = (uintptr_t) link; + uintptr_t const first_block_begin = (uintptr_t) first_block; + + _Heap_Block_set_size( link, first_block_begin - link_begin ); + + last_block->size_and_flag |= HEAP_PREV_BLOCK_USED; +} + +bool _Heap_Extend( + Heap_Control *heap, + void *extend_area_begin_ptr, + uintptr_t extend_area_size, + uintptr_t *extended_size_ptr +) +{ + Heap_Statistics *const stats = &heap->stats; + Heap_Block *const first_block = heap->first_block; + Heap_Block *start_block = first_block; + Heap_Block *merge_below_block = NULL; + Heap_Block *merge_above_block = NULL; + Heap_Block *link_below_block = NULL; + Heap_Block *link_above_block = NULL; + Heap_Block *extend_first_block = NULL; + Heap_Block *extend_last_block = NULL; + uintptr_t const page_size = heap->page_size; + uintptr_t const min_block_size = heap->min_block_size; + uintptr_t const extend_area_begin = (uintptr_t) extend_area_begin_ptr; + uintptr_t const extend_area_end = extend_area_begin + extend_area_size; + uintptr_t const free_size = stats->free_size; + uintptr_t extend_first_block_size = 0; + uintptr_t extended_size = 0; + bool extend_area_ok = false; + + if ( extend_area_end < extend_area_begin ) { + return false; + } + + extend_area_ok = _Heap_Get_first_and_last_block( + extend_area_begin, + extend_area_size, + page_size, + min_block_size, + &extend_first_block, + &extend_last_block + ); + if (!extend_area_ok ) { + /* For simplicity we reject extend areas that are too small */ + return false; + } + + do { + uintptr_t const sub_area_begin = (start_block != first_block) ? + (uintptr_t) start_block : heap->area_begin; + uintptr_t const sub_area_end = start_block->prev_size; + Heap_Block *const end_block = + _Heap_Block_of_alloc_area( sub_area_end, page_size ); + + if ( + sub_area_end > extend_area_begin && extend_area_end > sub_area_begin + ) { + return false; + } + + if ( extend_area_end == sub_area_begin ) { + merge_below_block = start_block; + } else if ( extend_area_end < sub_area_end ) { + link_below_block = start_block; + } + + if ( sub_area_end == extend_area_begin ) { + start_block->prev_size = extend_area_end; + + merge_above_block = end_block; + } else if ( sub_area_end < extend_area_begin ) { + link_above_block = end_block; + } + + start_block = _Heap_Block_at( end_block, _Heap_Block_size( end_block ) ); + } while ( start_block != first_block ); + + if ( extend_area_begin < heap->area_begin ) { + heap->area_begin = extend_area_begin; + } else if ( heap->area_end < extend_area_end ) { + heap->area_end = extend_area_end; + } + + extend_first_block_size = + (uintptr_t) extend_last_block - (uintptr_t) extend_first_block; + + extend_first_block->prev_size = extend_area_end; + extend_first_block->size_and_flag = + extend_first_block_size | HEAP_PREV_BLOCK_USED; + _Heap_Protection_block_initialize( heap, extend_first_block ); + + extend_last_block->prev_size = extend_first_block_size; + extend_last_block->size_and_flag = 0; + _Heap_Protection_block_initialize( heap, extend_last_block ); + + if ( (uintptr_t) extend_first_block < (uintptr_t) heap->first_block ) { + heap->first_block = extend_first_block; + } else if ( (uintptr_t) extend_last_block > (uintptr_t) heap->last_block ) { + heap->last_block = extend_last_block; + } + + if ( merge_below_block != NULL ) { + _Heap_Merge_below( heap, extend_area_begin, merge_below_block ); + } else if ( link_below_block != NULL ) { + _Heap_Link_below( + link_below_block, + extend_last_block + ); + } + + if ( merge_above_block != NULL ) { + _Heap_Merge_above( heap, merge_above_block, extend_area_end ); + } else if ( link_above_block != NULL ) { + _Heap_Link_above( + link_above_block, + extend_first_block, + extend_last_block + ); + } + + if ( merge_below_block == NULL && merge_above_block == NULL ) { + _Heap_Free_block( heap, extend_first_block ); + } + + _Heap_Set_last_block_size( heap ); + + extended_size = stats->free_size - free_size; + + /* Statistics */ + stats->size += extended_size; + + if ( extended_size_ptr != NULL ) + *extended_size_ptr = extended_size; + + return true; +} diff --git a/cpukit/score/src/heapfree.c b/cpukit/score/src/heapfree.c new file mode 100644 index 0000000000..25a1e6964d --- /dev/null +++ b/cpukit/score/src/heapfree.c @@ -0,0 +1,215 @@ +/** + * @file + * + * @ingroup ScoreHeap + * + * @brief Heap Handler implementation. + */ + +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/heap.h> + +#ifndef HEAP_PROTECTION + #define _Heap_Protection_determine_block_free( heap, block ) true +#else + static void _Heap_Protection_delay_block_free( + Heap_Control *heap, + Heap_Block *block + ) + { + uintptr_t *const pattern_begin = (uintptr_t *) + _Heap_Alloc_area_of_block( block ); + uintptr_t *const pattern_end = (uintptr_t *) + ((uintptr_t) block + _Heap_Block_size( block ) + HEAP_ALLOC_BONUS); + uintptr_t const delayed_free_block_count = + heap->Protection.delayed_free_block_count; + uintptr_t *current = NULL; + + block->Protection_begin.next_delayed_free_block = block; + block->Protection_begin.task = _Thread_Executing; + + if ( delayed_free_block_count > 0 ) { + Heap_Block *const last = heap->Protection.last_delayed_free_block; + + last->Protection_begin.next_delayed_free_block = block; + } else { + heap->Protection.first_delayed_free_block = block; + } + heap->Protection.last_delayed_free_block = block; + heap->Protection.delayed_free_block_count = delayed_free_block_count + 1; + + for ( current = pattern_begin; current != pattern_end; ++current ) { + *current = HEAP_FREE_PATTERN; + } + } + + static void _Heap_Protection_check_free_block( + Heap_Control *heap, + Heap_Block *block + ) + { + uintptr_t *const pattern_begin = (uintptr_t *) + _Heap_Alloc_area_of_block( block ); + uintptr_t *const pattern_end = (uintptr_t *) + ((uintptr_t) block + _Heap_Block_size( block ) + HEAP_ALLOC_BONUS); + uintptr_t *current = NULL; + + for ( current = pattern_begin; current != pattern_end; ++current ) { + if ( *current != HEAP_FREE_PATTERN ) { + _Heap_Protection_block_error( heap, block ); + break; + } + } + } + + static bool _Heap_Protection_determine_block_free( + Heap_Control *heap, + Heap_Block *block + ) + { + bool do_free = true; + + /* + * Sometimes after a free the allocated area is still in use. An example + * is the task stack of a thread that deletes itself. The thread dispatch + * disable level is a way to detect this use case. + */ + if ( _Thread_Dispatch_disable_level == 0 ) { + Heap_Block *const next = block->Protection_begin.next_delayed_free_block; + if ( next == NULL ) { + _Heap_Protection_delay_block_free( heap, block ); + do_free = false; + } else if ( next == HEAP_PROTECTION_OBOLUS ) { + _Heap_Protection_check_free_block( heap, block ); + } else { + _Heap_Protection_block_error( heap, block ); + } + } + + return do_free; + } +#endif + +bool _Heap_Free( Heap_Control *heap, void *alloc_begin_ptr ) +{ + Heap_Statistics *const stats = &heap->stats; + uintptr_t alloc_begin; + Heap_Block *block; + Heap_Block *next_block = NULL; + uintptr_t block_size = 0; + uintptr_t next_block_size = 0; + bool next_is_free = false; + + /* + * If NULL return true so a free on NULL is considered a valid release. This + * is a special case that could be handled by the in heap check how-ever that + * would result in false being returned which is wrong. + */ + if ( alloc_begin_ptr == NULL ) { + return true; + } + + alloc_begin = (uintptr_t) alloc_begin_ptr; + block = _Heap_Block_of_alloc_area( alloc_begin, heap->page_size ); + + if ( !_Heap_Is_block_in_heap( heap, block ) ) { + return false; + } + + _Heap_Protection_block_check( heap, block ); + + block_size = _Heap_Block_size( block ); + next_block = _Heap_Block_at( block, block_size ); + + if ( !_Heap_Is_block_in_heap( heap, next_block ) ) { + return false; + } + + _Heap_Protection_block_check( heap, next_block ); + + if ( !_Heap_Is_prev_used( next_block ) ) { + _Heap_Protection_block_error( heap, block ); + return false; + } + + if ( !_Heap_Protection_determine_block_free( heap, block ) ) { + return true; + } + + next_block_size = _Heap_Block_size( next_block ); + next_is_free = next_block != heap->last_block + && !_Heap_Is_prev_used( _Heap_Block_at( next_block, next_block_size )); + + if ( !_Heap_Is_prev_used( block ) ) { + uintptr_t const prev_size = block->prev_size; + Heap_Block * const prev_block = _Heap_Block_at( block, -prev_size ); + + if ( !_Heap_Is_block_in_heap( heap, prev_block ) ) { + _HAssert( false ); + return( false ); + } + + /* As we always coalesce free blocks, the block that preceedes prev_block + must have been used. */ + if ( !_Heap_Is_prev_used ( prev_block) ) { + _HAssert( false ); + return( false ); + } + + if ( next_is_free ) { /* coalesce both */ + uintptr_t const size = block_size + prev_size + next_block_size; + _Heap_Free_list_remove( next_block ); + stats->free_blocks -= 1; + prev_block->size_and_flag = size | HEAP_PREV_BLOCK_USED; + next_block = _Heap_Block_at( prev_block, size ); + _HAssert(!_Heap_Is_prev_used( next_block)); + next_block->prev_size = size; + } else { /* coalesce prev */ + uintptr_t const size = block_size + prev_size; + prev_block->size_and_flag = size | HEAP_PREV_BLOCK_USED; + next_block->size_and_flag &= ~HEAP_PREV_BLOCK_USED; + next_block->prev_size = size; + } + } else if ( next_is_free ) { /* coalesce next */ + uintptr_t const size = block_size + next_block_size; + _Heap_Free_list_replace( next_block, block ); + block->size_and_flag = size | HEAP_PREV_BLOCK_USED; + next_block = _Heap_Block_at( block, size ); + next_block->prev_size = size; + } else { /* no coalesce */ + /* Add 'block' to the head of the free blocks list as it tends to + produce less fragmentation than adding to the tail. */ + _Heap_Free_list_insert_after( _Heap_Free_list_head( heap), block ); + block->size_and_flag = block_size | HEAP_PREV_BLOCK_USED; + next_block->size_and_flag &= ~HEAP_PREV_BLOCK_USED; + next_block->prev_size = block_size; + + /* Statistics */ + ++stats->free_blocks; + if ( stats->max_free_blocks < stats->free_blocks ) { + stats->max_free_blocks = stats->free_blocks; + } + } + + /* Statistics */ + --stats->used_blocks; + ++stats->frees; + stats->free_size += block_size; + + return( true ); +} diff --git a/cpukit/score/src/heapgetfreeinfo.c b/cpukit/score/src/heapgetfreeinfo.c new file mode 100644 index 0000000000..406ed81d39 --- /dev/null +++ b/cpukit/score/src/heapgetfreeinfo.c @@ -0,0 +1,54 @@ +/** + * @file + * + * @ingroup ScoreHeap + * + * @brief Heap Handler implementation. + */ + +/* + * COPYRIGHT (c) 1989-2004. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/heap.h> + +void _Heap_Get_free_information( + Heap_Control *the_heap, + Heap_Information *info +) +{ + Heap_Block *the_block; + Heap_Block *const tail = _Heap_Free_list_tail(the_heap); + + info->number = 0; + info->largest = 0; + info->total = 0; + + for(the_block = _Heap_Free_list_first(the_heap); + the_block != tail; + the_block = the_block->next) + { + uint32_t const the_size = _Heap_Block_size(the_block); + + /* As we always coalesce free blocks, prev block must have been used. */ + _HAssert(_Heap_Is_prev_used(the_block)); + + info->number++; + info->total += the_size; + if ( info->largest < the_size ) + info->largest = the_size; + } +} diff --git a/cpukit/score/src/heapgetinfo.c b/cpukit/score/src/heapgetinfo.c new file mode 100644 index 0000000000..bcb5a7f68d --- /dev/null +++ b/cpukit/score/src/heapgetinfo.c @@ -0,0 +1,57 @@ +/** + * @file + * + * @ingroup ScoreHeap + * + * @brief Heap Handler implementation. + */ + +/* + * COPYRIGHT (c) 1989-2009. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> + +#include <rtems/system.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/heap.h> + +void _Heap_Get_information( + Heap_Control *the_heap, + Heap_Information_block *the_info +) +{ + Heap_Block *the_block = the_heap->first_block; + Heap_Block *const end = the_heap->last_block; + + memset(the_info, 0, sizeof(*the_info)); + + while ( the_block != end ) { + uintptr_t const the_size = _Heap_Block_size(the_block); + Heap_Block *const next_block = _Heap_Block_at(the_block, the_size); + Heap_Information *info; + + if ( _Heap_Is_prev_used(next_block) ) + info = &the_info->Used; + else + info = &the_info->Free; + + info->number++; + info->total += the_size; + if ( info->largest < the_size ) + info->largest = the_size; + + the_block = next_block; + } +} diff --git a/cpukit/score/src/heapresizeblock.c b/cpukit/score/src/heapresizeblock.c new file mode 100644 index 0000000000..2d3528645f --- /dev/null +++ b/cpukit/score/src/heapresizeblock.c @@ -0,0 +1,119 @@ +/** + * @file + * + * @ingroup ScoreHeap + * + * @brief Heap Handler implementation. + */ + +/* + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * Copyright (c) 2009 embedded brains GmbH. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/heap.h> + +static Heap_Resize_status _Heap_Resize_block_checked( + Heap_Control *heap, + Heap_Block *block, + uintptr_t alloc_begin, + uintptr_t new_alloc_size, + uintptr_t *old_size, + uintptr_t *new_size +) +{ + Heap_Statistics *const stats = &heap->stats; + + uintptr_t const block_begin = (uintptr_t) block; + uintptr_t block_size = _Heap_Block_size( block ); + uintptr_t block_end = block_begin + block_size; + + uintptr_t alloc_size = block_end - alloc_begin + HEAP_ALLOC_BONUS; + + Heap_Block *next_block = _Heap_Block_at( block, block_size ); + uintptr_t next_block_size = _Heap_Block_size( next_block ); + bool next_block_is_free = _Heap_Is_free( next_block );; + + _HAssert( _Heap_Is_block_in_heap( heap, next_block ) ); + _HAssert( _Heap_Is_prev_used( next_block ) ); + + *old_size = alloc_size; + + if ( next_block_is_free ) { + block_size += next_block_size; + alloc_size += next_block_size; + } + + if ( new_alloc_size > alloc_size ) { + return HEAP_RESIZE_UNSATISFIED; + } + + if ( next_block_is_free ) { + _Heap_Block_set_size( block, block_size ); + + _Heap_Free_list_remove( next_block ); + + next_block = _Heap_Block_at( block, block_size ); + next_block->size_and_flag |= HEAP_PREV_BLOCK_USED; + + /* Statistics */ + --stats->free_blocks; + stats->free_size -= next_block_size; + } + + block = _Heap_Block_allocate( heap, block, alloc_begin, new_alloc_size ); + + block_size = _Heap_Block_size( block ); + next_block = _Heap_Block_at( block, block_size ); + *new_size = (uintptr_t) next_block - alloc_begin + HEAP_ALLOC_BONUS; + + /* Statistics */ + ++stats->resizes; + + return HEAP_RESIZE_SUCCESSFUL; +} + +Heap_Resize_status _Heap_Resize_block( + Heap_Control *heap, + void *alloc_begin_ptr, + uintptr_t new_alloc_size, + uintptr_t *old_size, + uintptr_t *new_size +) +{ + uintptr_t const page_size = heap->page_size; + + uintptr_t const alloc_begin = (uintptr_t) alloc_begin_ptr; + + Heap_Block *const block = _Heap_Block_of_alloc_area( alloc_begin, page_size ); + + *old_size = 0; + *new_size = 0; + + if ( _Heap_Is_block_in_heap( heap, block ) ) { + _Heap_Protection_block_check( heap, block ); + return _Heap_Resize_block_checked( + heap, + block, + alloc_begin, + new_alloc_size, + old_size, + new_size + ); + } + return HEAP_RESIZE_FATAL_ERROR; +} diff --git a/cpukit/score/src/heapsizeofuserarea.c b/cpukit/score/src/heapsizeofuserarea.c new file mode 100644 index 0000000000..0a8b150811 --- /dev/null +++ b/cpukit/score/src/heapsizeofuserarea.c @@ -0,0 +1,58 @@ +/** + * @file + * + * @ingroup ScoreHeap + * + * @brief Heap Handler implementation. + */ + +/* + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/heap.h> + +bool _Heap_Size_of_alloc_area( + Heap_Control *heap, + void *alloc_begin_ptr, + uintptr_t *alloc_size +) +{ + uintptr_t const page_size = heap->page_size; + uintptr_t const alloc_begin = (uintptr_t) alloc_begin_ptr; + Heap_Block *block = _Heap_Block_of_alloc_area( alloc_begin, page_size ); + Heap_Block *next_block = NULL; + uintptr_t block_size = 0; + + if ( !_Heap_Is_block_in_heap( heap, block ) ) { + return false; + } + + block_size = _Heap_Block_size( block ); + next_block = _Heap_Block_at( block, block_size ); + + if ( + !_Heap_Is_block_in_heap( heap, next_block ) + || !_Heap_Is_prev_used( next_block ) + ) { + return false; + } + + *alloc_size = (uintptr_t) next_block + HEAP_ALLOC_BONUS - alloc_begin; + + return true; +} + diff --git a/cpukit/score/src/heapwalk.c b/cpukit/score/src/heapwalk.c new file mode 100644 index 0000000000..fae0bd6330 --- /dev/null +++ b/cpukit/score/src/heapwalk.c @@ -0,0 +1,421 @@ +/** + * @file + * + * @ingroup ScoreHeap + * + * @brief Heap Handler implementation. + */ + +/* + * COPYRIGHT ( c ) 1989-2007. + * On-Line Applications Research Corporation ( OAR ). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/address.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/heap.h> +#include <rtems/score/interr.h> +#include <rtems/bspIo.h> + +typedef void (*Heap_Walk_printer)(int, bool, const char*, ...); + +static void _Heap_Walk_print_nothing( + int source, + bool error, + const char *fmt, + ... +) +{ + /* Do nothing */ +} + +static void _Heap_Walk_print( int source, bool error, const char *fmt, ... ) +{ + va_list ap; + + if ( error ) { + printk( "FAIL[%d]: ", source ); + } else { + printk( "PASS[%d]: ", source ); + } + + va_start( ap, fmt ); + vprintk( fmt, ap ); + va_end( ap ); +} + +static bool _Heap_Walk_check_free_list( + int source, + Heap_Walk_printer printer, + Heap_Control *heap +) +{ + uintptr_t const page_size = heap->page_size; + const Heap_Block *const free_list_tail = _Heap_Free_list_tail( heap ); + const Heap_Block *const first_free_block = _Heap_Free_list_first( heap ); + const Heap_Block *prev_block = free_list_tail; + const Heap_Block *free_block = first_free_block; + + while ( free_block != free_list_tail ) { + if ( !_Heap_Is_block_in_heap( heap, free_block ) ) { + (*printer)( + source, + true, + "free block 0x%08x: not in heap\n", + free_block + ); + + return false; + } + + if ( + !_Heap_Is_aligned( _Heap_Alloc_area_of_block( free_block ), page_size ) + ) { + (*printer)( + source, + true, + "free block 0x%08x: alloc area not page aligned\n", + free_block + ); + + return false; + } + + if ( _Heap_Is_used( free_block ) ) { + (*printer)( + source, + true, + "free block 0x%08x: is used\n", + free_block + ); + + return false; + } + + if ( free_block->prev != prev_block ) { + (*printer)( + source, + true, + "free block 0x%08x: invalid previous block 0x%08x\n", + free_block, + free_block->prev + ); + + return false; + } + + prev_block = free_block; + free_block = free_block->next; + } + + return true; +} + +static bool _Heap_Walk_is_in_free_list( + Heap_Control *heap, + Heap_Block *block +) +{ + const Heap_Block *const free_list_tail = _Heap_Free_list_tail( heap ); + const Heap_Block *free_block = _Heap_Free_list_first( heap ); + + while ( free_block != free_list_tail ) { + if ( free_block == block ) { + return true; + } + free_block = free_block->next; + } + + return false; +} + +static bool _Heap_Walk_check_control( + int source, + Heap_Walk_printer printer, + Heap_Control *heap +) +{ + uintptr_t const page_size = heap->page_size; + uintptr_t const min_block_size = heap->min_block_size; + Heap_Block *const first_free_block = _Heap_Free_list_first( heap ); + Heap_Block *const last_free_block = _Heap_Free_list_last( heap ); + Heap_Block *const first_block = heap->first_block; + Heap_Block *const last_block = heap->last_block; + + (*printer)( + source, + false, + "page size %u, min block size %u\n" + "\tarea begin 0x%08x, area end 0x%08x\n" + "\tfirst block 0x%08x, last block 0x%08x\n" + "\tfirst free 0x%08x, last free 0x%08x\n", + page_size, min_block_size, + heap->area_begin, heap->area_end, + first_block, last_block, + first_free_block, last_free_block + ); + + if ( page_size == 0 ) { + (*printer)( source, true, "page size is zero\n" ); + + return false; + } + + if ( !_Addresses_Is_aligned( (void *) page_size ) ) { + (*printer)( + source, + true, + "page size %u not CPU aligned\n", + page_size + ); + + return false; + } + + if ( !_Heap_Is_aligned( min_block_size, page_size ) ) { + (*printer)( + source, + true, + "min block size %u not page aligned\n", + min_block_size + ); + + return false; + } + + if ( + !_Heap_Is_aligned( _Heap_Alloc_area_of_block( first_block ), page_size ) + ) { + (*printer)( + source, + true, + "first block 0x%08x: alloc area not page aligned\n", + first_block + ); + + return false; + } + + if ( !_Heap_Is_prev_used( first_block ) ) { + (*printer)( + source, + true, + "first block: HEAP_PREV_BLOCK_USED is cleared\n" + ); + + return false; + } + + if ( _Heap_Is_free( last_block ) ) { + (*printer)( + source, + true, + "last block: is free\n" + ); + + return false; + } + + if ( + _Heap_Block_at( last_block, _Heap_Block_size( last_block ) ) != first_block + ) { + (*printer)( + source, + true, + "last block: next block is not the first block\n" + ); + + return false; + } + + return _Heap_Walk_check_free_list( source, printer, heap ); +} + +static bool _Heap_Walk_check_free_block( + int source, + Heap_Walk_printer printer, + Heap_Control *heap, + Heap_Block *block +) +{ + Heap_Block *const free_list_tail = _Heap_Free_list_tail( heap ); + Heap_Block *const free_list_head = _Heap_Free_list_head( heap ); + Heap_Block *const first_free_block = _Heap_Free_list_first( heap ); + Heap_Block *const last_free_block = _Heap_Free_list_last( heap ); + bool const prev_used = _Heap_Is_prev_used( block ); + uintptr_t const block_size = _Heap_Block_size( block ); + Heap_Block *const next_block = _Heap_Block_at( block, block_size ); + + (*printer)( + source, + false, + "block 0x%08x: size %u, prev 0x%08x%s, next 0x%08x%s\n", + block, + block_size, + block->prev, + block->prev == first_free_block ? + " (= first free)" + : (block->prev == free_list_head ? " (= head)" : ""), + block->next, + block->next == last_free_block ? + " (= last free)" + : (block->next == free_list_tail ? " (= tail)" : "") + ); + + if ( block_size != next_block->prev_size ) { + (*printer)( + source, + true, + "block 0x%08x: size %u != size %u (in next block 0x%08x)\n", + block, + block_size, + next_block->prev_size, + next_block + ); + + return false; + } + + if ( !prev_used ) { + (*printer)( + source, + true, + "block 0x%08x: two consecutive blocks are free\n", + block + ); + + return false; + } + + if ( !_Heap_Walk_is_in_free_list( heap, block ) ) { + (*printer)( + source, + true, + "block 0x%08x: free block not in free list\n", + block + ); + + return false; + } + + return true; +} + +bool _Heap_Walk( + Heap_Control *heap, + int source, + bool dump +) +{ + uintptr_t const page_size = heap->page_size; + uintptr_t const min_block_size = heap->min_block_size; + Heap_Block *const first_block = heap->first_block; + Heap_Block *const last_block = heap->last_block; + Heap_Block *block = first_block; + Heap_Walk_printer printer = dump ? + _Heap_Walk_print : _Heap_Walk_print_nothing; + + if ( !_System_state_Is_up( _System_state_Get() ) ) { + return true; + } + + if ( !_Heap_Walk_check_control( source, printer, heap ) ) { + return false; + } + + do { + uintptr_t const block_begin = (uintptr_t) block; + uintptr_t const block_size = _Heap_Block_size( block ); + bool const prev_used = _Heap_Is_prev_used( block ); + Heap_Block *const next_block = _Heap_Block_at( block, block_size ); + uintptr_t const next_block_begin = (uintptr_t) next_block; + bool const is_not_last_block = block != last_block; + + if ( !_Heap_Is_block_in_heap( heap, next_block ) ) { + (*printer)( + source, + true, + "block 0x%08x: next block 0x%08x not in heap\n", + block, + next_block + ); + + return false; + } + + if ( !_Heap_Is_aligned( block_size, page_size ) && is_not_last_block ) { + (*printer)( + source, + true, + "block 0x%08x: block size %u not page aligned\n", + block, + block_size + ); + + return false; + } + + if ( block_size < min_block_size && is_not_last_block ) { + (*printer)( + source, + true, + "block 0x%08x: size %u < min block size %u\n", + block, + block_size, + min_block_size + ); + + return false; + } + + if ( next_block_begin <= block_begin && is_not_last_block ) { + (*printer)( + source, + true, + "block 0x%08x: next block 0x%08x is not a successor\n", + block, + next_block + ); + + return false; + } + + if ( !_Heap_Is_prev_used( next_block ) ) { + if ( !_Heap_Walk_check_free_block( source, printer, heap, block ) ) { + return false; + } + } else if (prev_used) { + (*printer)( + source, + false, + "block 0x%08x: size %u\n", + block, + block_size + ); + } else { + (*printer)( + source, + false, + "block 0x%08x: size %u, prev_size %u\n", + block, + block_size, + block->prev_size + ); + } + + block = next_block; + } while ( block != first_block ); + + return true; +} diff --git a/cpukit/score/src/interr.c b/cpukit/score/src/interr.c new file mode 100644 index 0000000000..cd9e09121e --- /dev/null +++ b/cpukit/score/src/interr.c @@ -0,0 +1,65 @@ +/* + * Internal Error Handler + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/interr.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/userext.h> + +/*PAGE + * + * _Internal_error_Occurred + * + * This routine will invoke the fatal error handler supplied by the user + * followed by the the default one provided by the executive. The default + * error handler assumes no hardware is present to help inform the user + * of the problem. Halt stores the error code in a known register, + * disables interrupts, and halts the CPU. If the CPU does not have a + * halt instruction, it will loop to itself. + * + * Input parameters: + * the_source - what subsystem the error originated in + * is_internal - if the error was internally generated + * the_error - fatal error status code + * + * Output parameters: + * As much information as possible is stored in a CPU dependent fashion. + * See the CPU dependent code for more information. + * + * NOTE: The the_error is not necessarily a directive status code. + */ + +void _Internal_error_Occurred( + Internal_errors_Source the_source, + bool is_internal, + Internal_errors_t the_error +) +{ + + _Internal_errors_What_happened.the_source = the_source; + _Internal_errors_What_happened.is_internal = is_internal; + _Internal_errors_What_happened.the_error = the_error; + + _User_extensions_Fatal( the_source, is_internal, the_error ); + + _System_state_Set( SYSTEM_STATE_FAILED ); + + _CPU_Fatal_halt( the_error ); + + /* will not return from this routine */ + while (true); +} diff --git a/cpukit/score/src/isr.c b/cpukit/score/src/isr.c new file mode 100644 index 0000000000..799bb08dbb --- /dev/null +++ b/cpukit/score/src/isr.c @@ -0,0 +1,83 @@ +/* + * ISR Handler + * + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/stack.h> +#include <rtems/score/interr.h> +#include <rtems/score/wkspace.h> +#include <rtems/config.h> + +/* _ISR_Handler_initialization + * + * This routine initializes the ISR handler. + * + * Input parameters: NONE + * + * Output parameters: NONE + */ + +void _ISR_Handler_initialization( void ) +{ + _ISR_Nest_level = 0; + +#if (CPU_SIMPLE_VECTORED_INTERRUPTS == TRUE) + _ISR_Vector_table = _Workspace_Allocate_or_fatal_error( + sizeof(ISR_Handler_entry) * ISR_NUMBER_OF_VECTORS + ); +#endif + + _CPU_Initialize_vectors(); + +#if ( CPU_ALLOCATE_INTERRUPT_STACK == TRUE ) + + if ( !_Stack_Is_enough(Configuration.interrupt_stack_size) ) + _Internal_error_Occurred( + INTERNAL_ERROR_CORE, + true, + INTERNAL_ERROR_INTERRUPT_STACK_TOO_SMALL + ); + + _CPU_Interrupt_stack_low = _Workspace_Allocate_or_fatal_error( + Configuration.interrupt_stack_size + ); + + _CPU_Interrupt_stack_high = _Addresses_Add_offset( + _CPU_Interrupt_stack_low, + Configuration.interrupt_stack_size + ); + +#if (CPU_STACK_ALIGNMENT != 0) + _CPU_Interrupt_stack_high = (void *) + ((uintptr_t) _CPU_Interrupt_stack_high & ~(CPU_STACK_ALIGNMENT - 1)); +#endif + + /* Interrupt stack might have to be aligned and/or setup + * in a specific way. + */ +#if defined(_CPU_Interrupt_stack_setup) + _CPU_Interrupt_stack_setup(_CPU_Interrupt_stack_low, _CPU_Interrupt_stack_high); +#endif + +#endif + +#if ( CPU_HAS_HARDWARE_INTERRUPT_STACK == TRUE ) + _CPU_Install_interrupt_stack(); +#endif + +} diff --git a/cpukit/score/src/iterateoverthreads.c b/cpukit/score/src/iterateoverthreads.c new file mode 100644 index 0000000000..8c65becc4c --- /dev/null +++ b/cpukit/score/src/iterateoverthreads.c @@ -0,0 +1,55 @@ +/* + * rtems_iterate_over_all_threads + * + * This function operates by as follows: + * for all threads + * invoke specified function + * + * COPYRIGHT (c) 1989-2010. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/thread.h> + +void rtems_iterate_over_all_threads(rtems_per_thread_routine routine) +{ + uint32_t i; + uint32_t api_index; + Thread_Control *the_thread; + Objects_Information *information; + + if ( !routine ) + return; + + for ( api_index = 1 ; api_index <= OBJECTS_APIS_LAST ; api_index++ ) { + #if !defined(RTEMS_POSIX_API) || defined(RTEMS_DEBUG) + if ( !_Objects_Information_table[ api_index ] ) + continue; + #endif + + information = _Objects_Information_table[ api_index ][ 1 ]; + if ( !information ) + continue; + + for ( i=1 ; i <= information->maximum ; i++ ) { + the_thread = (Thread_Control *)information->local_table[ i ]; + + if ( !the_thread ) + continue; + + (*routine)(the_thread); + } + } + +} diff --git a/cpukit/score/src/mpci.c b/cpukit/score/src/mpci.c new file mode 100644 index 0000000000..d8f68ebc89 --- /dev/null +++ b/cpukit/score/src/mpci.c @@ -0,0 +1,540 @@ +/* + * Multiprocessing Communications Interface (MPCI) Handler + * + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/mpci.h> +#include <rtems/score/mppkt.h> +#endif +#include <rtems/config.h> +#include <rtems/score/cpu.h> +#include <rtems/score/interr.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/tqdata.h> +#include <rtems/score/watchdog.h> +#include <rtems/score/sysstate.h> + +#include <rtems/score/coresem.h> +#include <rtems/config.h> + +/** + * This is the core semaphore which the MPCI Receive Server blocks on. + */ +CORE_semaphore_Control _MPCI_Semaphore; + +/*PAGE + * + * _MPCI_Handler_initialization + * + * This subprogram performs the initialization necessary for this handler. + */ + +void _MPCI_Handler_initialization( + uint32_t timeout_status +) +{ + CORE_semaphore_Attributes attributes; + MPCI_Control *users_mpci_table; + + users_mpci_table = _Configuration_MP_table->User_mpci_table; + + if ( _System_state_Is_multiprocessing && !users_mpci_table ) + _Internal_error_Occurred( + INTERNAL_ERROR_CORE, + true, + INTERNAL_ERROR_NO_MPCI + ); + + _MPCI_table = users_mpci_table; + + if ( !_System_state_Is_multiprocessing ) + return; + + /* + * Register the MP Process Packet routine. + */ + + _MPCI_Register_packet_processor( + MP_PACKET_MPCI_INTERNAL, + _MPCI_Internal_packets_Process_packet + ); + + /* + * Create the counting semaphore used by the MPCI Receive Server. + */ + + attributes.discipline = CORE_SEMAPHORE_DISCIPLINES_FIFO; + + _CORE_semaphore_Initialize( + &_MPCI_Semaphore, + &attributes, /* the_semaphore_attributes */ + 0 /* initial_value */ + ); + + _Thread_queue_Initialize( + &_MPCI_Remote_blocked_threads, + THREAD_QUEUE_DISCIPLINE_FIFO, + STATES_WAITING_FOR_RPC_REPLY, + timeout_status + ); +} + +/*PAGE + * + * _MPCI_Create_server + * + * This subprogram creates the MPCI receive server. + */ + +void _MPCI_Create_server( void ) +{ + Objects_Name name; + + + if ( !_System_state_Is_multiprocessing ) + return; + + /* + * Initialize the MPCI Receive Server + */ + + _MPCI_Receive_server_tcb = _Thread_Internal_allocate(); + + name.name_u32 = _Objects_Build_name( 'M', 'P', 'C', 'I' ); + _Thread_Initialize( + &_Thread_Internal_information, + _MPCI_Receive_server_tcb, + NULL, /* allocate the stack */ + _Stack_Minimum() + + CPU_MPCI_RECEIVE_SERVER_EXTRA_STACK + + _Configuration_MP_table->extra_mpci_receive_server_stack, + CPU_ALL_TASKS_ARE_FP, + PRIORITY_MINIMUM, + false, /* no preempt */ + THREAD_CPU_BUDGET_ALGORITHM_NONE, + NULL, /* no budget algorithm callout */ + 0, /* all interrupts enabled */ + name + ); + + _Thread_Start( + _MPCI_Receive_server_tcb, + THREAD_START_NUMERIC, + (void *) _MPCI_Receive_server, + NULL, + 0 + ); +} + +/*PAGE + * + * _MPCI_Initialization + * + * This subprogram initializes the MPCI driver by + * invoking the user provided MPCI initialization callout. + */ + +void _MPCI_Initialization ( void ) +{ + (*_MPCI_table->initialization)(); +} + +/*PAGE + * + * _MPCI_Register_packet_processor + * + * This routine registers the MPCI packet processor for the + * designated object class. + */ + +void _MPCI_Register_packet_processor( + MP_packet_Classes the_class, + MPCI_Packet_processor the_packet_processor + +) +{ + _MPCI_Packet_processors[ the_class ] = the_packet_processor; +} + +/*PAGE + * + * _MPCI_Get_packet + * + * This subprogram obtains a packet by invoking the user provided + * MPCI get packet callout. + */ + +MP_packet_Prefix *_MPCI_Get_packet ( void ) +{ + MP_packet_Prefix *the_packet; + + (*_MPCI_table->get_packet)( &the_packet ); + + if ( the_packet == NULL ) + _Internal_error_Occurred( + INTERNAL_ERROR_CORE, + true, + INTERNAL_ERROR_OUT_OF_PACKETS + ); + + /* + * Put in a default timeout that will be used for + * all packets that do not otherwise have a timeout. + */ + + the_packet->timeout = MPCI_DEFAULT_TIMEOUT; + + return the_packet; +} + +/*PAGE + * + * _MPCI_Return_packet + * + * This subprogram returns a packet by invoking the user provided + * MPCI return packet callout. + */ + +void _MPCI_Return_packet ( + MP_packet_Prefix *the_packet +) +{ + (*_MPCI_table->return_packet)( the_packet ); +} + +/*PAGE + * + * _MPCI_Send_process_packet + * + * This subprogram sends a process packet by invoking the user provided + * MPCI send callout. + */ + +void _MPCI_Send_process_packet ( + uint32_t destination, + MP_packet_Prefix *the_packet +) +{ + the_packet->source_tid = _Thread_Executing->Object.id; + the_packet->to_convert = + ( the_packet->to_convert - sizeof(MP_packet_Prefix) ) / sizeof(uint32_t); + + (*_MPCI_table->send_packet)( destination, the_packet ); +} + +/*PAGE + * + * _MPCI_Send_request_packet + * + * This subprogram sends a request packet by invoking the user provided + * MPCI send callout. + */ + +uint32_t _MPCI_Send_request_packet ( + uint32_t destination, + MP_packet_Prefix *the_packet, + States_Control extra_state +) +{ + the_packet->source_tid = _Thread_Executing->Object.id; + the_packet->source_priority = _Thread_Executing->current_priority; + the_packet->to_convert = + ( the_packet->to_convert - sizeof(MP_packet_Prefix) ) / sizeof(uint32_t); + + _Thread_Executing->Wait.id = the_packet->id; + + _Thread_Executing->Wait.queue = &_MPCI_Remote_blocked_threads; + + _Thread_Disable_dispatch(); + + (*_MPCI_table->send_packet)( destination, the_packet ); + + _Thread_queue_Enter_critical_section( &_MPCI_Remote_blocked_threads ); + + /* + * See if we need a default timeout + */ + + if (the_packet->timeout == MPCI_DEFAULT_TIMEOUT) + the_packet->timeout = _MPCI_table->default_timeout; + + _Thread_queue_Enqueue( &_MPCI_Remote_blocked_threads, the_packet->timeout ); + + _Thread_Executing->current_state = + _States_Set( extra_state, _Thread_Executing->current_state ); + + _Thread_Enable_dispatch(); + + return _Thread_Executing->Wait.return_code; +} + +/*PAGE + * + * _MPCI_Send_response_packet + * + * This subprogram sends a response packet by invoking the user provided + * MPCI send callout. + */ + +void _MPCI_Send_response_packet ( + uint32_t destination, + MP_packet_Prefix *the_packet +) +{ + the_packet->source_tid = _Thread_Executing->Object.id; + + (*_MPCI_table->send_packet)( destination, the_packet ); +} + +/*PAGE + * + * _MPCI_Receive_packet + * + * This subprogram receives a packet by invoking the user provided + * MPCI receive callout. + */ + +MP_packet_Prefix *_MPCI_Receive_packet ( void ) +{ + MP_packet_Prefix *the_packet; + + (*_MPCI_table->receive_packet)( &the_packet ); + + return the_packet; +} + +/*PAGE + * + * _MPCI_Process_response + * + * This subprogram obtains a packet by invoking the user provided + * MPCI get packet callout. + */ + +Thread_Control *_MPCI_Process_response ( + MP_packet_Prefix *the_packet +) +{ + Thread_Control *the_thread; + Objects_Locations location; + + the_thread = _Thread_Get( the_packet->id, &location ); + switch ( location ) { + case OBJECTS_ERROR: +#if defined(RTEMS_MULTIPROCESSING) + case OBJECTS_REMOTE: +#endif + the_thread = NULL; /* IMPOSSIBLE */ + break; + case OBJECTS_LOCAL: + _Thread_queue_Extract( &_MPCI_Remote_blocked_threads, the_thread ); + the_thread->Wait.return_code = the_packet->return_code; + _Thread_Unnest_dispatch(); + break; + } + + return the_thread; +} + +/*PAGE + * + * _MPCI_Receive_server + * + */ + +Thread _MPCI_Receive_server( + uint32_t ignored +) +{ + + MP_packet_Prefix *the_packet; + MPCI_Packet_processor the_function; + Thread_Control *executing; + + executing = _Thread_Executing; + + for ( ; ; ) { + + executing->receive_packet = NULL; + + _Thread_Disable_dispatch(); + _CORE_semaphore_Seize( &_MPCI_Semaphore, 0, true, WATCHDOG_NO_TIMEOUT ); + _Thread_Enable_dispatch(); + + for ( ; ; ) { + the_packet = _MPCI_Receive_packet(); + + if ( !the_packet ) + break; + + executing->receive_packet = the_packet; + + if ( !_Mp_packet_Is_valid_packet_class ( the_packet->the_class ) ) + break; + + the_function = _MPCI_Packet_processors[ the_packet->the_class ]; + + if ( !the_function ) + _Internal_error_Occurred( + INTERNAL_ERROR_CORE, + true, + INTERNAL_ERROR_BAD_PACKET + ); + + (*the_function)( the_packet ); + } + } + + return 0; /* unreached - only to remove warnings */ +} + +/*PAGE + * + * _MPCI_Announce + * + */ + +void _MPCI_Announce ( void ) +{ + _Thread_Disable_dispatch(); + (void) _CORE_semaphore_Surrender( &_MPCI_Semaphore, 0, 0 ); + _Thread_Enable_dispatch(); +} + +/*PAGE + * + * _MPCI_Internal_packets_Send_process_packet + * + */ + +void _MPCI_Internal_packets_Send_process_packet ( + MPCI_Internal_Remote_operations operation +) +{ + MPCI_Internal_packet *the_packet; + + switch ( operation ) { + + case MPCI_PACKETS_SYSTEM_VERIFY: + + the_packet = _MPCI_Internal_packets_Get_packet(); + the_packet->Prefix.the_class = MP_PACKET_MPCI_INTERNAL; + the_packet->Prefix.length = sizeof ( MPCI_Internal_packet ); + the_packet->Prefix.to_convert = sizeof ( MPCI_Internal_packet ); + the_packet->operation = operation; + + the_packet->maximum_nodes = _Objects_Maximum_nodes; + + the_packet->maximum_global_objects = _Objects_MP_Maximum_global_objects; + + _MPCI_Send_process_packet( MPCI_ALL_NODES, &the_packet->Prefix ); + break; + } +} + +/*PAGE + * + * _MPCI_Internal_packets_Send_request_packet + * + * This subprogram is not needed since there are no request + * packets to be sent by this manager. + * + */ + +/*PAGE + * + * _MPCI_Internal_packets_Send_response_packet + * + * This subprogram is not needed since there are no response + * packets to be sent by this manager. + * + */ + +/*PAGE + * + * + * _MPCI_Internal_packets_Process_packet + * + */ + +void _MPCI_Internal_packets_Process_packet ( + MP_packet_Prefix *the_packet_prefix +) +{ + MPCI_Internal_packet *the_packet; + uint32_t maximum_nodes; + uint32_t maximum_global_objects; + + the_packet = (MPCI_Internal_packet *) the_packet_prefix; + + switch ( the_packet->operation ) { + + case MPCI_PACKETS_SYSTEM_VERIFY: + + maximum_nodes = the_packet->maximum_nodes; + maximum_global_objects = the_packet->maximum_global_objects; + if ( maximum_nodes != _Objects_Maximum_nodes || + maximum_global_objects != _Objects_MP_Maximum_global_objects ) { + + _MPCI_Return_packet( the_packet_prefix ); + + _Internal_error_Occurred( + INTERNAL_ERROR_CORE, + true, + INTERNAL_ERROR_INCONSISTENT_MP_INFORMATION + ); + } + + _MPCI_Return_packet( the_packet_prefix ); + + break; + } +} + +/*PAGE + * + * _MPCI_Internal_packets_Send_object_was_deleted + * + * This subprogram is not needed since there are no objects + * deleted by this manager. + * + */ + +/*PAGE + * + * _MPCI_Internal_packets_Send_extract_proxy + * + * This subprogram is not needed since there are no objects + * deleted by this manager. + * + */ + +/*PAGE + * + * _MPCI_Internal_packets_Get_packet + * + */ + +MPCI_Internal_packet *_MPCI_Internal_packets_Get_packet ( void ) +{ + return ( (MPCI_Internal_packet *) _MPCI_Get_packet() ); +} + +/* end of file */ diff --git a/cpukit/score/src/objectallocate.c b/cpukit/score/src/objectallocate.c new file mode 100644 index 0000000000..ac98945a74 --- /dev/null +++ b/cpukit/score/src/objectallocate.c @@ -0,0 +1,102 @@ +/* + * Object Handler + * + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/address.h> +#include <rtems/score/chain.h> +#include <rtems/score/object.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/objectmp.h> +#endif +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/isr.h> + +/* #define RTEMS_DEBUG_OBJECT_ALLOCATION */ + +#if defined(RTEMS_DEBUG_OBJECT_ALLOCATION) +#include <rtems/bspIo.h> +#endif + +/*PAGE + * + * _Objects_Allocate + * + * DESCRIPTION: + * + * This function allocates a object control block from + * the inactive chain of free object control blocks. + */ + +Objects_Control *_Objects_Allocate( + Objects_Information *information +) +{ + Objects_Control *the_object; + + /* + * If the application is using the optional manager stubs and + * still attempts to create the object, the information block + * should be all zeroed out because it is in the BSS. So let's + * check that code for this manager is even present. + */ + if ( information->size == 0 ) + return NULL; + + /* + * OK. The manager should be initialized and configured to have objects. + * With any luck, it is safe to attempt to allocate an object. + */ + the_object = (Objects_Control *) _Chain_Get( &information->Inactive ); + + if ( information->auto_extend ) { + /* + * If the list is empty then we are out of objects and need to + * extend information base. + */ + + if ( !the_object ) { + _Objects_Extend_information( information ); + the_object = (Objects_Control *) _Chain_Get( &information->Inactive ); + } + + if ( the_object ) { + uint32_t block; + + block = (uint32_t) _Objects_Get_index( the_object->id ) - + _Objects_Get_index( information->minimum_id ); + block /= information->allocation_size; + + information->inactive_per_block[ block ]--; + information->inactive--; + } + } + +#if defined(RTEMS_DEBUG_OBJECT_ALLOCATION) + if ( !the_object ) { + printk( + "OBJECT ALLOCATION FAILURE! API/Class %d/%d\n", + information->the_api, + information->the_class + ); + } +#endif + + return the_object; +} diff --git a/cpukit/score/src/objectapimaximumclass.c b/cpukit/score/src/objectapimaximumclass.c new file mode 100644 index 0000000000..bb61371278 --- /dev/null +++ b/cpukit/score/src/objectapimaximumclass.c @@ -0,0 +1,36 @@ +/* + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/object.h> + +unsigned int _Objects_API_maximum_class( + uint32_t api +) +{ + switch (api) { + case OBJECTS_INTERNAL_API: + return OBJECTS_INTERNAL_CLASSES_LAST; + case OBJECTS_CLASSIC_API: + return OBJECTS_RTEMS_CLASSES_LAST; + case OBJECTS_POSIX_API: + return OBJECTS_POSIX_CLASSES_LAST; + case OBJECTS_NO_API: + default: + break; + } + return 0; +} + diff --git a/cpukit/score/src/objectclose.c b/cpukit/score/src/objectclose.c new file mode 100644 index 0000000000..1ed76b7fbe --- /dev/null +++ b/cpukit/score/src/objectclose.c @@ -0,0 +1,28 @@ +/* + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/score/wkspace.h> + +void _Objects_Close( + Objects_Information *information, + Objects_Control *the_object +) +{ + _Objects_Invalidate_Id( information, the_object ); + + _Objects_Namespace_remove( information, the_object ); +} diff --git a/cpukit/score/src/objectextendinformation.c b/cpukit/score/src/objectextendinformation.c new file mode 100644 index 0000000000..0839e0f6be --- /dev/null +++ b/cpukit/score/src/objectextendinformation.c @@ -0,0 +1,266 @@ +/* + * Object Handler + * + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/address.h> +#include <rtems/score/chain.h> +#include <rtems/score/object.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/objectmp.h> +#endif +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/isr.h> + +#include <string.h> /* for memcpy() */ + +/*PAGE + * + * _Objects_Extend_information + * + * This routine extends all object information related data structures. + * + * Input parameters: + * information - object information table + * + * Output parameters: NONE + */ + +void _Objects_Extend_information( + Objects_Information *information +) +{ + Objects_Control *the_object; + Chain_Control Inactive; + uint32_t block_count; + uint32_t block; + uint32_t index_base; + uint32_t minimum_index; + uint32_t index; + uint32_t maximum; + size_t block_size; + void *new_object_block; + bool do_extend; + + /* + * Search for a free block of indexes. If we do NOT need to allocate or + * extend the block table, then we will change do_extend. + */ + do_extend = true; + minimum_index = _Objects_Get_index( information->minimum_id ); + index_base = minimum_index; + block = 0; + + /* if ( information->maximum < minimum_index ) */ + if ( information->object_blocks == NULL ) + block_count = 0; + else { + block_count = information->maximum / information->allocation_size; + + for ( ; block < block_count; block++ ) { + if ( information->object_blocks[ block ] == NULL ) { + do_extend = false; + break; + } else + index_base += information->allocation_size; + } + } + + maximum = (uint32_t) information->maximum + information->allocation_size; + + /* + * We need to limit the number of objects to the maximum number + * representable in the index portion of the object Id. In the + * case of 16-bit Ids, this is only 256 object instances. + */ + if ( maximum > OBJECTS_ID_FINAL_INDEX ) { + return; + } + + /* + * Allocate the name table, and the objects and if it fails either return or + * generate a fatal error depending on auto-extending being active. + */ + block_size = information->allocation_size * information->size; + if ( information->auto_extend ) { + new_object_block = _Workspace_Allocate( block_size ); + if ( !new_object_block ) + return; + } else { + new_object_block = _Workspace_Allocate_or_fatal_error( block_size ); + } + + /* + * Do we need to grow the tables? + */ + if ( do_extend ) { + ISR_Level level; + void **object_blocks; + uint32_t *inactive_per_block; + Objects_Control **local_table; + void *old_tables; + size_t block_size; + + /* + * Growing the tables means allocating a new area, doing a copy and + * updating the information table. + * + * If the maximum is minimum we do not have a table to copy. First + * time through. + * + * The allocation has : + * + * void *objects[block_count]; + * uint32_t inactive_count[block_count]; + * Objects_Control *local_table[maximum]; + * + * This is the order in memory. Watch changing the order. See the memcpy + * below. + */ + + /* + * Up the block count and maximum + */ + block_count++; + + /* + * Allocate the tables and break it up. + */ + block_size = block_count * + (sizeof(void *) + sizeof(uint32_t) + sizeof(Objects_Name *)) + + ((maximum + minimum_index) * sizeof(Objects_Control *)); + object_blocks = (void**) _Workspace_Allocate( block_size ); + + if ( !object_blocks ) { + _Workspace_Free( new_object_block ); + return; + } + + /* + * Break the block into the various sections. + */ + inactive_per_block = (uint32_t *) _Addresses_Add_offset( + object_blocks, block_count * sizeof(void*) ); + local_table = (Objects_Control **) _Addresses_Add_offset( + inactive_per_block, block_count * sizeof(uint32_t) ); + + /* + * Take the block count down. Saves all the (block_count - 1) + * in the copies. + */ + block_count--; + + if ( information->maximum > minimum_index ) { + + /* + * Copy each section of the table over. This has to be performed as + * separate parts as size of each block has changed. + */ + + memcpy( object_blocks, + information->object_blocks, + block_count * sizeof(void*) ); + memcpy( inactive_per_block, + information->inactive_per_block, + block_count * sizeof(uint32_t) ); + memcpy( local_table, + information->local_table, + (information->maximum + minimum_index) * sizeof(Objects_Control *) ); + } else { + + /* + * Deal with the special case of the 0 to minimum_index + */ + for ( index = 0; index < minimum_index; index++ ) { + local_table[ index ] = NULL; + } + } + + /* + * Initialise the new entries in the table. + */ + object_blocks[block_count] = NULL; + inactive_per_block[block_count] = 0; + + for ( index=index_base ; + index < ( information->allocation_size + index_base ); + index++ ) { + local_table[ index ] = NULL; + } + + _ISR_Disable( level ); + + old_tables = information->object_blocks; + + information->object_blocks = object_blocks; + information->inactive_per_block = inactive_per_block; + information->local_table = local_table; + information->maximum = (Objects_Maximum) maximum; + information->maximum_id = _Objects_Build_id( + information->the_api, + information->the_class, + _Objects_Local_node, + information->maximum + ); + + _ISR_Enable( level ); + + _Workspace_Free( old_tables ); + + block_count++; + } + + /* + * Assign the new object block to the object block table. + */ + information->object_blocks[ block ] = new_object_block; + + /* + * Initialize objects .. add to a local chain first. + */ + _Chain_Initialize( + &Inactive, + information->object_blocks[ block ], + information->allocation_size, + information->size + ); + + /* + * Move from the local chain, initialise, then append to the inactive chain + */ + index = index_base; + + while ((the_object = (Objects_Control *) _Chain_Get( &Inactive )) != NULL ) { + + the_object->id = _Objects_Build_id( + information->the_api, + information->the_class, + _Objects_Local_node, + index + ); + + _Chain_Append( &information->Inactive, &the_object->Node ); + + index++; + } + + information->inactive_per_block[ block ] = information->allocation_size; + information->inactive = + (Objects_Maximum)(information->inactive + information->allocation_size); +} diff --git a/cpukit/score/src/objectfree.c b/cpukit/score/src/objectfree.c new file mode 100644 index 0000000000..f74394d0fa --- /dev/null +++ b/cpukit/score/src/objectfree.c @@ -0,0 +1,69 @@ +/* + * Object Handler + * + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/address.h> +#include <rtems/score/chain.h> +#include <rtems/score/object.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/objectmp.h> +#endif +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/isr.h> + +/*PAGE + * + * _Objects_Free + * + * DESCRIPTION: + * + * This function frees a object control block to the + * inactive chain of free object control blocks. + */ + +void _Objects_Free( + Objects_Information *information, + Objects_Control *the_object +) +{ + uint32_t allocation_size = information->allocation_size; + + _Chain_Append( &information->Inactive, &the_object->Node ); + + if ( information->auto_extend ) { + uint32_t block; + + block = (uint32_t) (_Objects_Get_index( the_object->id ) - + _Objects_Get_index( information->minimum_id )); + block /= information->allocation_size; + + information->inactive_per_block[ block ]++; + information->inactive++; + + /* + * Check if the threshold level has been met of + * 1.5 x allocation_size are free. + */ + + if ( information->inactive > ( allocation_size + ( allocation_size >> 1 ) ) ) { + _Objects_Shrink_information( information ); + } + } +} diff --git a/cpukit/score/src/objectget.c b/cpukit/score/src/objectget.c new file mode 100644 index 0000000000..2abcc389fb --- /dev/null +++ b/cpukit/score/src/objectget.c @@ -0,0 +1,108 @@ +/* + * Object Handler + * + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/address.h> +#include <rtems/score/chain.h> +#include <rtems/score/object.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/objectmp.h> +#endif +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/isr.h> + +/*PAGE + * + * _Objects_Get + * + * This routine sets the object pointer for the given + * object id based on the given object information structure. + * + * Input parameters: + * information - pointer to entry in table for this class + * id - object id to search for + * location - address of where to store the location + * + * Output parameters: + * returns - address of object if local + * location - one of the following: + * OBJECTS_ERROR - invalid object ID + * OBJECTS_REMOTE - remote object + * OBJECTS_LOCAL - local object + */ + +Objects_Control *_Objects_Get( + Objects_Information *information, + Objects_Id id, + Objects_Locations *location +) +{ + Objects_Control *the_object; + uint32_t index; + + /* + * Extract the index portion of an Id in a way that produces a valid + * index for objects within this class and an invalid value for objects + * outside this class. + * + * If the Id matches the api, class, and node but index portion is 0, + * then the subtraction will underflow and the addition of 1 will + * result in a 0 index. The zeroth element in the local_table is + * always NULL. + * + * If the Id is valid but the object has not been created yet, then + * the local_table entry will be NULL. + */ + index = id - information->minimum_id + 1; + + /* + * If the index is less than maximum, then it is OK to use it to + * index into the local_table array. + */ + if ( index <= information->maximum ) { + _Thread_Disable_dispatch(); + if ( (the_object = information->local_table[ index ]) != NULL ) { + *location = OBJECTS_LOCAL; + return the_object; + } + + /* + * Valid Id for this API, Class and Node but the object has not + * been allocated yet. + */ + _Thread_Enable_dispatch(); + *location = OBJECTS_ERROR; + return NULL; + } + + /* + * Object Id is not within this API and Class on this node. So + * it may be global in a multiprocessing system. But it is clearly + * invalid on a single processor system. + */ + *location = OBJECTS_ERROR; + +#if defined(RTEMS_MULTIPROCESSING) + _Objects_MP_Is_remote( information, id, location, &the_object ); + return the_object; +#else + return NULL; +#endif +} diff --git a/cpukit/score/src/objectgetinfo.c b/cpukit/score/src/objectgetinfo.c new file mode 100644 index 0000000000..da3e79713e --- /dev/null +++ b/cpukit/score/src/objectgetinfo.c @@ -0,0 +1,62 @@ +/* + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> + +Objects_Information *_Objects_Get_information( + Objects_APIs the_api, + uint16_t the_class +) +{ + Objects_Information *info; + int the_class_api_maximum; + + if ( !the_class ) + return NULL; + + /* + * This call implicitly validates the_api so we do not call + * _Objects_Is_api_valid above here. + */ + the_class_api_maximum = _Objects_API_maximum_class( the_api ); + if ( the_class_api_maximum == 0 ) + return NULL; + + if ( the_class > (uint32_t) the_class_api_maximum ) + return NULL; + + if ( !_Objects_Information_table[ the_api ] ) + return NULL; + + info = _Objects_Information_table[ the_api ][ the_class ]; + if ( !info ) + return NULL; + + /* + * In a multprocessing configuration, we may access remote objects. + * Thus we may have 0 local instances and still have a valid object + * pointer. + */ + #if !defined(RTEMS_MULTIPROCESSING) + if ( info->maximum == 0 ) + return NULL; + #endif + + return info; +} + diff --git a/cpukit/score/src/objectgetinfoid.c b/cpukit/score/src/objectgetinfoid.c new file mode 100644 index 0000000000..729135a9dc --- /dev/null +++ b/cpukit/score/src/objectgetinfoid.c @@ -0,0 +1,28 @@ +/* + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/score/thread.h> + +Objects_Information *_Objects_Get_information_id( + Objects_Id id +) +{ + return _Objects_Get_information( + _Objects_Get_API( id ), + _Objects_Get_class( id ) + ); +} diff --git a/cpukit/score/src/objectgetisr.c b/cpukit/score/src/objectgetisr.c new file mode 100644 index 0000000000..aca5f0d059 --- /dev/null +++ b/cpukit/score/src/objectgetisr.c @@ -0,0 +1,86 @@ +/* + * Object Handler + * + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/address.h> +#include <rtems/score/chain.h> +#include <rtems/score/object.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/objectmp.h> +#endif +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/isr.h> + +/*PAGE + * + * _Objects_Get_isr_disable + * + * This routine sets the object pointer for the given + * object id based on the given object information structure. + * + * Input parameters: + * information - pointer to entry in table for this class + * id - object id to search for + * location - address of where to store the location + * level - pointer to previous interrupt level + * + * Output parameters: + * returns - address of object if local + * location - one of the following: + * OBJECTS_ERROR - invalid object ID + * OBJECTS_REMOTE - remote object + * OBJECTS_LOCAL - local object + * *level - previous interrupt level + */ + +Objects_Control *_Objects_Get_isr_disable( + Objects_Information *information, + Objects_Id id, + Objects_Locations *location, + ISR_Level *level_p +) +{ + Objects_Control *the_object; + uint32_t index; + ISR_Level level; + + index = id - information->minimum_id + 1; + + _ISR_Disable( level ); + if ( information->maximum >= index ) { + if ( (the_object = information->local_table[ index ]) != NULL ) { + *location = OBJECTS_LOCAL; + *level_p = level; + return the_object; + } + _ISR_Enable( level ); + *location = OBJECTS_ERROR; + return NULL; + } + _ISR_Enable( level ); + *location = OBJECTS_ERROR; + +#if defined(RTEMS_MULTIPROCESSING) + _Objects_MP_Is_remote( information, id, location, &the_object ); + return the_object; +#else + return NULL; +#endif +} diff --git a/cpukit/score/src/objectgetnameasstring.c b/cpukit/score/src/objectgetnameasstring.c new file mode 100644 index 0000000000..4c15cd9811 --- /dev/null +++ b/cpukit/score/src/objectgetnameasstring.c @@ -0,0 +1,96 @@ +/* + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/score/thread.h> +#include <stdlib.h> +#include <ctype.h> +#include <inttypes.h> + +/* + * This method objects the name of an object and returns its name + * in the form of a C string. It attempts to be careful about + * overflowing the user's string and about returning unprintable characters. + */ + +char *_Objects_Get_name_as_string( + Objects_Id id, + size_t length, + char *name +) +{ + Objects_Information *information; + const char *s; + char *d; + uint32_t i; + char lname[5]; + Objects_Control *the_object; + Objects_Locations location; + Objects_Id tmpId; + + if ( length == 0 ) + return NULL; + + if ( name == NULL ) + return NULL; + + tmpId = (id == OBJECTS_ID_OF_SELF) ? _Thread_Executing->Object.id : id; + + information = _Objects_Get_information_id( tmpId ); + if ( !information ) + return NULL; + + the_object = _Objects_Get( information, tmpId, &location ); + switch ( location ) { + +#if defined(RTEMS_MULTIPROCESSING) + case OBJECTS_REMOTE: + /* not supported */ +#endif + case OBJECTS_ERROR: + return NULL; + + case OBJECTS_LOCAL: + + #if defined(RTEMS_SCORE_OBJECT_ENABLE_STRING_NAMES) + if ( information->is_string ) { + s = the_object->name.name_p; + } else + #endif + { + uint32_t u32_name = (uint32_t) the_object->name.name_u32; + + lname[ 0 ] = (u32_name >> 24) & 0xff; + lname[ 1 ] = (u32_name >> 16) & 0xff; + lname[ 2 ] = (u32_name >> 8) & 0xff; + lname[ 3 ] = (u32_name >> 0) & 0xff; + lname[ 4 ] = '\0'; + s = lname; + } + + d = name; + if ( s ) { + for ( i=0 ; i<(length-1) && *s ; i++, s++, d++ ) { + *d = (isprint((unsigned char)*s)) ? *s : '*'; + } + } + *d = '\0'; + + _Thread_Enable_dispatch(); + return name; + } + return NULL; /* unreachable path */ +} diff --git a/cpukit/score/src/objectgetnext.c b/cpukit/score/src/objectgetnext.c new file mode 100644 index 0000000000..206dbf3134 --- /dev/null +++ b/cpukit/score/src/objectgetnext.c @@ -0,0 +1,103 @@ +/* + * Object Handler + * + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/address.h> +#include <rtems/score/chain.h> +#include <rtems/score/object.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/objectmp.h> +#endif +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/isr.h> + +/*PAGE + * + * _Objects_Get_next + * + * Like _Objects_Get, but considers the 'id' as a "hint" and + * finds next valid one after that point. + * Mostly used for monitor and debug traversal of an object. + * + * Input parameters: + * information - pointer to entry in table for this class + * id - object id to search for + * location - address of where to store the location + * next_id - address to store next id to try + * + * Output parameters: + * returns - address of object if local + * location - one of the following: + * OBJECTS_ERROR - invalid object ID + * OBJECTS_REMOTE - remote object + * OBJECTS_LOCAL - local object + * next_id - will contain a reasonable "next" id to continue traversal + * + * NOTE: + * assumes can add '1' to an id to get to next index. + */ + +Objects_Control * +_Objects_Get_next( + Objects_Information *information, + Objects_Id id, + Objects_Locations *location_p, + Objects_Id *next_id_p +) +{ + Objects_Control *object; + Objects_Id next_id; + + if ( !information ) + return NULL; + + if ( !location_p ) + return NULL; + + if ( !next_id_p ) + return NULL; + + if (_Objects_Get_index(id) == OBJECTS_ID_INITIAL_INDEX) + next_id = information->minimum_id; + else + next_id = id; + + do { + /* walked off end of list? */ + if (_Objects_Get_index(next_id) > information->maximum) + { + *location_p = OBJECTS_ERROR; + goto final; + } + + /* try to grab one */ + object = _Objects_Get(information, next_id, location_p); + + next_id++; + + } while (*location_p != OBJECTS_LOCAL); + + *next_id_p = next_id; + return object; + +final: + *next_id_p = OBJECTS_ID_FINAL; + return 0; +} diff --git a/cpukit/score/src/objectgetnoprotection.c b/cpukit/score/src/objectgetnoprotection.c new file mode 100644 index 0000000000..d969477747 --- /dev/null +++ b/cpukit/score/src/objectgetnoprotection.c @@ -0,0 +1,79 @@ +/* + * Object Handler -- Object Get + * + * + * COPYRIGHT (c) 1989-2002. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/address.h> +#include <rtems/score/chain.h> +#include <rtems/score/object.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/objectmp.h> +#endif +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/isr.h> + +/*PAGE + * + * _Objects_Get_no_protection + * + * This routine sets the object pointer for the given + * object id based on the given object information structure. + * + * Input parameters: + * information - pointer to entry in table for this class + * id - object id to search for + * location - address of where to store the location + * + * Output parameters: + * returns - address of object if local + * location - one of the following: + * OBJECTS_ERROR - invalid object ID + * OBJECTS_REMOTE - remote object + * OBJECTS_LOCAL - local object + */ + +Objects_Control *_Objects_Get_no_protection( + Objects_Information *information, + Objects_Id id, + Objects_Locations *location +) +{ + Objects_Control *the_object; + uint32_t index; + + /* + * You can't just extract the index portion or you can get tricked + * by a value between 1 and maximum. + */ + index = id - information->minimum_id + 1; + + if ( information->maximum >= index ) { + if ( (the_object = information->local_table[ index ]) != NULL ) { + *location = OBJECTS_LOCAL; + return the_object; + } + } + + /* + * This isn't supported or required yet for Global objects so + * if it isn't local, we don't find it. + */ + *location = OBJECTS_ERROR; + return NULL; +} diff --git a/cpukit/score/src/objectidtoname.c b/cpukit/score/src/objectidtoname.c new file mode 100644 index 0000000000..870d424986 --- /dev/null +++ b/cpukit/score/src/objectidtoname.c @@ -0,0 +1,79 @@ +/* + * Obtain Object Name Given ID + * + * + * COPYRIGHT (c) 1989-2003. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/score/thread.h> + +/* + * _Objects_Id_to_name + * + * DESCRIPTION: + * + * This routine returns the name associated with the given ID. + * + * INPUT: + * + * id - id of object to lookup name + * name - pointer to location in which to store name + * + */ +Objects_Name_or_id_lookup_errors _Objects_Id_to_name ( + Objects_Id id, + Objects_Name *name +) +{ + uint32_t the_api; + uint32_t the_class; + Objects_Id tmpId; + Objects_Information *information; + Objects_Control *the_object = (Objects_Control *) 0; + Objects_Locations ignored_location; + + /* + * Caller is trusted for name != NULL. + */ + + tmpId = (id == OBJECTS_ID_OF_SELF) ? _Thread_Executing->Object.id : id; + + the_api = _Objects_Get_API( tmpId ); + if ( !_Objects_Is_api_valid( the_api ) ) + return OBJECTS_INVALID_ID; + + if ( !_Objects_Information_table[ the_api ] ) + return OBJECTS_INVALID_ID; + + the_class = _Objects_Get_class( tmpId ); + + information = _Objects_Information_table[ the_api ][ the_class ]; + if ( !information ) + return OBJECTS_INVALID_ID; + + #if defined(RTEMS_SCORE_OBJECT_ENABLE_STRING_NAMES) + if ( information->is_string ) + return OBJECTS_INVALID_ID; + #endif + + the_object = _Objects_Get( information, tmpId, &ignored_location ); + if ( !the_object ) + return OBJECTS_INVALID_ID; + + *name = the_object->name; + _Thread_Enable_dispatch(); + return OBJECTS_NAME_OR_ID_LOOKUP_SUCCESSFUL; +} diff --git a/cpukit/score/src/objectinitializeinformation.c b/cpukit/score/src/objectinitializeinformation.c new file mode 100644 index 0000000000..b59b64ae97 --- /dev/null +++ b/cpukit/score/src/objectinitializeinformation.c @@ -0,0 +1,178 @@ +/* + * Object Handler Initialization per Object Class + * + * COPYRIGHT (c) 1989-2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/address.h> +#include <rtems/score/chain.h> +#include <rtems/score/object.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/objectmp.h> +#endif +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/isr.h> + +/*PAGE + * + * _Objects_Initialize_information + * + * This routine initializes all object information related data structures. + * + * Input parameters: + * information - object information table + * maximum - maximum objects of this class + * size - size of this object's control block + * is_string - true if names for this object are strings + * maximum_name_length - maximum length of each object's name + * When multiprocessing is configured, + * supports_global - true if this is a global object class + * extract_callout - pointer to threadq extract callout + * + * Output parameters: NONE + */ + +void _Objects_Initialize_information( + Objects_Information *information, + Objects_APIs the_api, + uint16_t the_class, + uint32_t maximum, + uint16_t size, + bool is_string, + uint32_t maximum_name_length +#if defined(RTEMS_MULTIPROCESSING) + , + bool supports_global, + Objects_Thread_queue_Extract_callout extract +#endif +) +{ + static Objects_Control *null_local_table = NULL; + uint32_t minimum_index; + uint32_t name_length; + uint32_t maximum_per_allocation; + #if defined(RTEMS_MULTIPROCESSING) + uint32_t index; + #endif + + information->the_api = the_api; + information->the_class = the_class; + information->size = size; + information->local_table = 0; + information->inactive_per_block = 0; + information->object_blocks = 0; + information->inactive = 0; + #if defined(RTEMS_SCORE_OBJECT_ENABLE_STRING_NAMES) + information->is_string = is_string; + #endif + + /* + * Set the maximum value to 0. It will be updated when objects are + * added to the inactive set from _Objects_Extend_information() + */ + information->maximum = 0; + + /* + * Register this Object Class in the Object Information Table. + */ + _Objects_Information_table[ the_api ][ the_class ] = information; + + /* + * Are we operating in limited or unlimited (e.g. auto-extend) mode. + */ + information->auto_extend = + (maximum & OBJECTS_UNLIMITED_OBJECTS) ? true : false; + maximum_per_allocation = maximum & ~OBJECTS_UNLIMITED_OBJECTS; + + /* + * Unlimited and maximum of zero is illogical. + */ + if ( information->auto_extend && maximum_per_allocation == 0) { + _Internal_error_Occurred( + INTERNAL_ERROR_CORE, + true, + INTERNAL_ERROR_UNLIMITED_AND_MAXIMUM_IS_0 + ); + } + + /* + * The allocation unit is the maximum value + */ + information->allocation_size = maximum_per_allocation; + + /* + * Provide a null local table entry for the case of any empty table. + */ + information->local_table = &null_local_table; + + /* + * Calculate minimum and maximum Id's + */ + minimum_index = (maximum_per_allocation == 0) ? 0 : 1; + information->minimum_id = + _Objects_Build_id( the_api, the_class, _Objects_Local_node, minimum_index ); + + /* + * Calculate the maximum name length + * + * NOTE: Always 4 bytes long in Class so aligned. It is POSIX name + * lengths that may be an odd number of bytes. + */ + name_length = maximum_name_length; + + #if defined(RTEMS_POSIX_API) + if ( name_length & (OBJECTS_NAME_ALIGNMENT-1) ) + name_length = (name_length + OBJECTS_NAME_ALIGNMENT) & + ~(OBJECTS_NAME_ALIGNMENT-1); + #endif + + information->name_length = name_length; + + _Chain_Initialize_empty( &information->Inactive ); + + /* + * Initialize objects .. if there are any + */ + if ( maximum_per_allocation ) { + /* + * Always have the maximum size available so the current performance + * figures are create are met. If the user moves past the maximum + * number then a performance hit is taken. + */ + _Objects_Extend_information( information ); + } + + /* + * Take care of multiprocessing + */ + #if defined(RTEMS_MULTIPROCESSING) + information->extract = extract; + + if ( (supports_global == true) && _System_state_Is_multiprocessing ) { + + information->global_table = + (Chain_Control *) _Workspace_Allocate_or_fatal_error( + (_Objects_Maximum_nodes + 1) * sizeof(Chain_Control) + ); + + for ( index=1; index <= _Objects_Maximum_nodes ; index++ ) + _Chain_Initialize_empty( &information->global_table[ index ] ); + } + else + information->global_table = NULL; + #endif +} diff --git a/cpukit/score/src/objectmp.c b/cpukit/score/src/objectmp.c new file mode 100644 index 0000000000..5564b52f1f --- /dev/null +++ b/cpukit/score/src/objectmp.c @@ -0,0 +1,307 @@ +/* + * Multiprocessing Support for the Object Handler + * + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/config.h> +#include <rtems/score/interr.h> +#include <rtems/score/object.h> +#include <rtems/score/wkspace.h> +#include <rtems/score/thread.h> + +/*PAGE + * + * _Objects_MP_Handler_early_initialization + * + */ +void _Objects_MP_Handler_early_initialization(void) +{ + uint32_t node; + uint32_t maximum_nodes; + + node = _Configuration_MP_table->node; + maximum_nodes = _Configuration_MP_table->maximum_nodes; + + if ( node < 1 || node > maximum_nodes ) + _Internal_error_Occurred( + INTERNAL_ERROR_CORE, + true, + INTERNAL_ERROR_INVALID_NODE + ); + + _Objects_Local_node = node; + _Objects_Maximum_nodes = maximum_nodes; +} + +/*PAGE + * + * _Objects_MP_Handler_initialization + * + */ + +void _Objects_MP_Handler_initialization(void) +{ + + uint32_t maximum_global_objects; + + maximum_global_objects = _Configuration_MP_table->maximum_global_objects; + + _Objects_MP_Maximum_global_objects = maximum_global_objects; + + if ( maximum_global_objects == 0 ) { + _Chain_Initialize_empty( &_Objects_MP_Inactive_global_objects ); + return; + } + + _Chain_Initialize( + &_Objects_MP_Inactive_global_objects, + _Workspace_Allocate_or_fatal_error( + maximum_global_objects * sizeof( Objects_MP_Control ) + ), + maximum_global_objects, + sizeof( Objects_MP_Control ) + ); + +} + +/*PAGE + * + * _Objects_MP_Open + * + */ + +void _Objects_MP_Open ( + Objects_Information *information, + Objects_MP_Control *the_global_object, + uint32_t the_name, /* XXX -- wrong for variable */ + Objects_Id the_id +) +{ + the_global_object->Object.id = the_id; + the_global_object->name = the_name; + + _Chain_Prepend( + &information->global_table[ _Objects_Get_node( the_id ) ], + &the_global_object->Object.Node + ); + +} + +/*PAGE + * + * _Objects_MP_Allocate_and_open + * + */ + +bool _Objects_MP_Allocate_and_open ( + Objects_Information *information, + uint32_t the_name, /* XXX -- wrong for variable */ + Objects_Id the_id, + bool is_fatal_error +) +{ + Objects_MP_Control *the_global_object; + + the_global_object = _Objects_MP_Allocate_global_object(); + if ( _Objects_MP_Is_null_global_object( the_global_object ) ) { + + if ( is_fatal_error == false ) + return false; + + _Internal_error_Occurred( + INTERNAL_ERROR_CORE, + true, + INTERNAL_ERROR_OUT_OF_GLOBAL_OBJECTS + ); + + } + + _Objects_MP_Open( information, the_global_object, the_name, the_id ); + + return true; +} + +/*PAGE + * + * _Objects_MP_Close + * + */ + +void _Objects_MP_Close ( + Objects_Information *information, + Objects_Id the_id +) +{ + Chain_Control *the_chain; + Chain_Node *the_node; + Objects_MP_Control *the_object; + + the_chain = &information->global_table[ _Objects_Get_node( the_id ) ]; + + for ( the_node = _Chain_First( the_chain ) ; + !_Chain_Is_tail( the_chain, the_node ) ; + the_node = _Chain_Next( the_node ) ) { + + the_object = (Objects_MP_Control *) the_node; + + if ( _Objects_Are_ids_equal( the_object->Object.id, the_id ) ) { + + _Chain_Extract( the_node ); + _Objects_MP_Free_global_object( the_object ); + return; + } + + } + + _Internal_error_Occurred( + INTERNAL_ERROR_CORE, + true, + INTERNAL_ERROR_INVALID_GLOBAL_ID + ); +} + +/*PAGE + * + * _Objects_MP_Global_name_search + * + */ + +Objects_Name_or_id_lookup_errors _Objects_MP_Global_name_search ( + Objects_Information *information, + Objects_Name the_name, + uint32_t nodes_to_search, + Objects_Id *the_id +) +{ + uint32_t low_node; + uint32_t high_node; + uint32_t node_index; + Chain_Control *the_chain; + Chain_Node *the_node; + Objects_MP_Control *the_object; + uint32_t name_to_use; + + name_to_use = the_name.name_u32; /* XXX only fixed length names */ + + if ( nodes_to_search > _Objects_Maximum_nodes ) + return OBJECTS_INVALID_NODE; + + if ( information->global_table == NULL ) + return OBJECTS_INVALID_NAME; + + if ( nodes_to_search == OBJECTS_SEARCH_ALL_NODES || + nodes_to_search == OBJECTS_SEARCH_OTHER_NODES ) { + low_node = 1; + high_node = _Objects_Maximum_nodes; + } else { + low_node = + high_node = nodes_to_search; + } + + _Thread_Disable_dispatch(); + + for ( node_index = low_node ; node_index <= high_node ; node_index++ ) { + + /* + * NOTE: The local node was search (if necessary) by + * _Objects_Name_to_id_XXX before this was invoked. + */ + + if ( !_Objects_Is_local_node( node_index ) ) { + the_chain = &information->global_table[ node_index ]; + + for ( the_node = _Chain_First( the_chain ) ; + !_Chain_Is_tail( the_chain, the_node ) ; + the_node = _Chain_Next( the_node ) ) { + + the_object = (Objects_MP_Control *) the_node; + + if ( the_object->name == name_to_use ) { + *the_id = the_object->Object.id; + _Thread_Enable_dispatch(); + return OBJECTS_NAME_OR_ID_LOOKUP_SUCCESSFUL; + } + } + } + } + + _Thread_Enable_dispatch(); + return OBJECTS_INVALID_NAME; +} + +/*PAGE + * + * _Objects_MP_Is_remote + * + */ + +void _Objects_MP_Is_remote ( + Objects_Information *information, + Objects_Id the_id, + Objects_Locations *location, + Objects_Control **the_object +) +{ + uint32_t node; + Chain_Control *the_chain; + Chain_Node *the_node; + Objects_MP_Control *the_global_object; + + node = _Objects_Get_node( the_id ); + + /* + * NOTE: The local node was search (if necessary) by + * _Objects_Name_to_id_XXX before this was invoked. + * + * The NODE field of an object id cannot be 0 + * because 0 is an invalid node number. + */ + + if ( node == 0 || + _Objects_Is_local_node( node ) || + node > _Objects_Maximum_nodes || + information->global_table == NULL ) { + + *location = OBJECTS_ERROR; + *the_object = NULL; + return; + } + + _Thread_Disable_dispatch(); + + the_chain = &information->global_table[ node ]; + + for ( the_node = _Chain_First( the_chain ) ; + !_Chain_Is_tail( the_chain, the_node ) ; + the_node = _Chain_Next( the_node ) ) { + + the_global_object = (Objects_MP_Control *) the_node; + + if ( _Objects_Are_ids_equal( the_global_object->Object.id, the_id ) ) { + _Thread_Unnest_dispatch(); + *location = OBJECTS_REMOTE; + *the_object = (Objects_Control *) the_global_object; + return; + } + } + + _Thread_Enable_dispatch(); + *location = OBJECTS_ERROR; + *the_object = NULL; + +} + diff --git a/cpukit/score/src/objectnamespaceremove.c b/cpukit/score/src/objectnamespaceremove.c new file mode 100644 index 0000000000..d6c0968f90 --- /dev/null +++ b/cpukit/score/src/objectnamespaceremove.c @@ -0,0 +1,40 @@ +/* + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/score/wkspace.h> + +void _Objects_Namespace_remove( + Objects_Information *information, + Objects_Control *the_object +) +{ + #if defined(RTEMS_SCORE_OBJECT_ENABLE_STRING_NAMES) + /* + * If this is a string format name, then free the memory. + */ + if ( information->is_string ) + _Workspace_Free( (void *)the_object->name.name_p ); + #endif + + /* + * Clear out either format. + */ + #if defined(RTEMS_SCORE_OBJECT_ENABLE_STRING_NAMES) + the_object->name.name_p = NULL; + #endif + the_object->name.name_u32 = 0; +} diff --git a/cpukit/score/src/objectnametoid.c b/cpukit/score/src/objectnametoid.c new file mode 100644 index 0000000000..9cd75a274c --- /dev/null +++ b/cpukit/score/src/objectnametoid.c @@ -0,0 +1,102 @@ +/* + * Object Handler + * + * COPYRIGHT (c) 1989-2010. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/address.h> +#include <rtems/score/chain.h> +#include <rtems/score/object.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/objectmp.h> +#endif +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/isr.h> + +/*PAGE + * + * _Objects_Name_to_id_u32 + * + * These kernel routines search the object table(s) for the given + * object name and returns the associated object id. + * + * Input parameters: + * information - object information + * name - user defined object name + * node - node indentifier (0 indicates any node) + * id - address of return ID + * + * Output parameters: + * id - object id + * OBJECTS_NAME_OR_ID_LOOKUP_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +Objects_Name_or_id_lookup_errors _Objects_Name_to_id_u32( + Objects_Information *information, + uint32_t name, + uint32_t node, + Objects_Id *id +) +{ + bool search_local_node; + Objects_Control *the_object; + uint32_t index; +#if defined(RTEMS_MULTIPROCESSING) + Objects_Name name_for_mp; +#endif + + /* ASSERT: information->is_string == false */ + + if ( !id ) + return OBJECTS_INVALID_ADDRESS; + + if ( name == 0 ) + return OBJECTS_INVALID_NAME; + + search_local_node = false; + + if ( information->maximum != 0 && + (node == OBJECTS_SEARCH_ALL_NODES || + node == OBJECTS_SEARCH_LOCAL_NODE || + _Objects_Is_local_node( node ) + )) + search_local_node = true; + + if ( search_local_node ) { + for ( index = 1; index <= information->maximum; index++ ) { + the_object = information->local_table[ index ]; + if ( !the_object ) + continue; + + if ( name == the_object->name.name_u32 ) { + *id = the_object->id; + return OBJECTS_NAME_OR_ID_LOOKUP_SUCCESSFUL; + } + } + } + +#if defined(RTEMS_MULTIPROCESSING) + if ( _Objects_Is_local_node( node ) || node == OBJECTS_SEARCH_LOCAL_NODE ) + return OBJECTS_INVALID_NAME; + + name_for_mp.name_u32 = name; + return _Objects_MP_Global_name_search( information, name_for_mp, node, id ); +#else + return OBJECTS_INVALID_NAME; +#endif +} diff --git a/cpukit/score/src/objectnametoidstring.c b/cpukit/score/src/objectnametoidstring.c new file mode 100644 index 0000000000..17b43d725d --- /dev/null +++ b/cpukit/score/src/objectnametoidstring.c @@ -0,0 +1,87 @@ +/* + * Object Handler - Object ID to Name (String) + * + * COPYRIGHT (c) 1989-2010. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> + +#include <rtems/system.h> +#include <rtems/score/address.h> +#include <rtems/score/chain.h> +#include <rtems/score/object.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/objectmp.h> +#endif +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/isr.h> + +#if defined(RTEMS_SCORE_OBJECT_ENABLE_STRING_NAMES) +/*PAGE + * + * _Objects_Name_to_id_string + * + * These kernel routines search the object table(s) for the given + * object name and returns the associated object id. + * + * Input parameters: + * information - object information + * name - user defined object name + * id - address of return ID + * + * Output parameters: + * id - object id + * OBJECTS_NAME_OR_ID_LOOKUP_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +Objects_Name_or_id_lookup_errors _Objects_Name_to_id_string( + Objects_Information *information, + const char *name, + Objects_Id *id +) +{ + Objects_Control *the_object; + uint32_t index; + + /* ASSERT: information->is_string == true */ + + if ( !id ) + return OBJECTS_INVALID_ADDRESS; + + if ( !name ) + return OBJECTS_INVALID_NAME; + + if ( information->maximum != 0 ) { + + for ( index = 1; index <= information->maximum; index++ ) { + the_object = information->local_table[ index ]; + if ( !the_object ) + continue; + + if ( !the_object->name.name_p ) + continue; + + if (!strncmp( name, the_object->name.name_p, information->name_length)) { + *id = the_object->id; + return OBJECTS_NAME_OR_ID_LOOKUP_SUCCESSFUL; + } + } + } + + return OBJECTS_INVALID_NAME; +} +#endif diff --git a/cpukit/score/src/objectsetname.c b/cpukit/score/src/objectsetname.c new file mode 100644 index 0000000000..793e0914dd --- /dev/null +++ b/cpukit/score/src/objectsetname.c @@ -0,0 +1,69 @@ +/* + * COPYRIGHT (c) 1989-2009. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> +#include <stdlib.h> +#include <ctype.h> +#include <inttypes.h> +#include <string.h> + + +/* + * This method sets the name of an object based upon a C string. + */ + +bool _Objects_Set_name( + Objects_Information *information, + Objects_Control *the_object, + const char *name +) +{ + size_t length; + const char *s; + + s = name; + length = strnlen( name, information->name_length ); + +#if defined(RTEMS_SCORE_OBJECT_ENABLE_STRING_NAMES) + if ( information->is_string ) { + char *d; + + d = _Workspace_Allocate( length + 1 ); + if ( !d ) + return false; + + _Workspace_Free( (void *)the_object->name.name_p ); + the_object->name.name_p = NULL; + + strncpy( d, name, length ); + d[length] = '\0'; + the_object->name.name_p = d; + } else +#endif + { + the_object->name.name_u32 = _Objects_Build_name( + ((0 <= length) ? s[ 0 ] : ' '), + ((1 < length) ? s[ 1 ] : ' '), + ((2 < length) ? s[ 2 ] : ' '), + ((3 < length) ? s[ 3 ] : ' ') + ); + + } + + return true; +} diff --git a/cpukit/score/src/objectshrinkinformation.c b/cpukit/score/src/objectshrinkinformation.c new file mode 100644 index 0000000000..18123fab68 --- /dev/null +++ b/cpukit/score/src/objectshrinkinformation.c @@ -0,0 +1,102 @@ +/* + * Object Handler + * + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/address.h> +#include <rtems/score/chain.h> +#include <rtems/score/object.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/objectmp.h> +#endif +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/isr.h> + +/*PAGE + * + * _Objects_Shrink_information + * + * This routine shrinks object information related data structures. + * The object's name and object space are released. The local_table + * etc block does not shrink. The InActive list needs to be scanned + * to find the objects are remove them. + * Input parameters: + * information - object information table + * the_block - the block to remove + * + * Output parameters: NONE + */ + +void _Objects_Shrink_information( + Objects_Information *information +) +{ + Objects_Control *the_object; + Objects_Control *extract_me; + uint32_t block_count; + uint32_t block; + uint32_t index_base; + uint32_t index; + + /* + * Search the list to find block or chunk with all objects inactive. + */ + + index_base = _Objects_Get_index( information->minimum_id ); + block_count = (information->maximum - index_base) / + information->allocation_size; + + for ( block = 0; block < block_count; block++ ) { + if ( information->inactive_per_block[ block ] == + information->allocation_size ) { + + /* + * Assume the Inactive chain is never empty at this point + */ + the_object = (Objects_Control *) _Chain_First( &information->Inactive ); + + do { + index = _Objects_Get_index( the_object->id ); + /* + * Get the next node before the node is extracted + */ + extract_me = the_object; + the_object = (Objects_Control *) the_object->Node.next; + if ((index >= index_base) && + (index < (index_base + information->allocation_size))) { + _Chain_Extract( &extract_me->Node ); + } + } + while ( the_object ); + /* + * Free the memory and reset the structures in the object' information + */ + + _Workspace_Free( information->object_blocks[ block ] ); + information->object_blocks[ block ] = NULL; + information->inactive_per_block[ block ] = 0; + + information->inactive -= information->allocation_size; + + return; + } + + index_base += information->allocation_size; + } +} diff --git a/cpukit/score/src/percpu.c b/cpukit/score/src/percpu.c new file mode 100644 index 0000000000..2d429b4db9 --- /dev/null +++ b/cpukit/score/src/percpu.c @@ -0,0 +1,64 @@ +/* + * COPYRIGHT (c) 1989-2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/thread.h> +#include <rtems/score/percpu.h> +#include <rtems/score/wkspace.h> +#include <rtems/score/wkspace.h> +#include <rtems/config.h> +#include <rtems/bspsmp.h> +#include <string.h> + +#if defined(RTEMS_SMP) + void _SMP_Handler_initialize(void) + { + int cpu; + size_t size; + uintptr_t ptr; + + /* + * Initialize per CPU structures. + */ + size = (_SMP_Processor_count) * sizeof(Per_CPU_Control); + memset( _Per_CPU_Information, '\0', size ); + + /* + * Initialize per cpu pointer table + */ + size = Configuration.interrupt_stack_size; + _Per_CPU_Information_p[0] = &_Per_CPU_Information[0]; + for (cpu=1 ; cpu < _SMP_Processor_count ; cpu++ ) { + Per_CPU_Control *p = &_Per_CPU_Information[cpu]; + + _Per_CPU_Information_p[cpu] = p; + + p->interrupt_stack_low = _Workspace_Allocate_or_fatal_error( size ); + + ptr = (uintptr_t) _Addresses_Add_offset( p->interrupt_stack_low, size ); + ptr &= ~CPU_STACK_ALIGNMENT; + p->interrupt_stack_high = (void *)ptr; + p->state = RTEMS_BSP_SMP_CPU_INITIAL_STATE; + RTEMS_COMPILER_MEMORY_BARRIER(); + } + } +#else + /* + * On single core systems, we can efficiently directly access a single + * statically allocated per cpu structure. And the fields are initialized + * as individual elements just like it has always been done. + */ + Per_CPU_Control _Per_CPU_Information[1]; +#endif diff --git a/cpukit/score/src/pheapallocate.c b/cpukit/score/src/pheapallocate.c new file mode 100644 index 0000000000..b4888dc8ea --- /dev/null +++ b/cpukit/score/src/pheapallocate.c @@ -0,0 +1,46 @@ +/** + * @file + * + * @ingroup ScoreProtHeap + * + * @brief Protected Heap Handler implementation. + */ + +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/protectedheap.h> + +void *_Protected_heap_Allocate_aligned_with_boundary( + Heap_Control *heap, + uintptr_t size, + uintptr_t alignment, + uintptr_t boundary +) +{ + void *p; + + _RTEMS_Lock_allocator(); + p = _Heap_Allocate_aligned_with_boundary( + heap, + size, + alignment, + boundary + ); + _RTEMS_Unlock_allocator(); + + return p; +} diff --git a/cpukit/score/src/pheapextend.c b/cpukit/score/src/pheapextend.c new file mode 100644 index 0000000000..e71fb1bd8c --- /dev/null +++ b/cpukit/score/src/pheapextend.c @@ -0,0 +1,41 @@ +/** + * @file + * + * @ingroup ScoreProtHeap + * + * @brief Protected Heap Handler implementation. + */ + +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/protectedheap.h> + +bool _Protected_heap_Extend( + Heap_Control *the_heap, + void *starting_address, + uintptr_t size +) +{ + bool extend_ok; + uintptr_t amount_extended; + + _RTEMS_Lock_allocator(); + extend_ok = _Heap_Extend(the_heap, starting_address, size, &amount_extended); + _RTEMS_Unlock_allocator(); + return extend_ok; +} + diff --git a/cpukit/score/src/pheapfree.c b/cpukit/score/src/pheapfree.c new file mode 100644 index 0000000000..eb57ded669 --- /dev/null +++ b/cpukit/score/src/pheapfree.c @@ -0,0 +1,38 @@ +/** + * @file + * + * @ingroup ScoreProtHeap + * + * @brief Protected Heap Handler implementation. + */ + +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/protectedheap.h> + +bool _Protected_heap_Free( + Heap_Control *the_heap, + void *start_address +) +{ + bool status; + + _RTEMS_Lock_allocator(); + status = _Heap_Free( the_heap, start_address ); + _RTEMS_Unlock_allocator(); + return status; +} diff --git a/cpukit/score/src/pheapgetblocksize.c b/cpukit/score/src/pheapgetblocksize.c new file mode 100644 index 0000000000..0591abdd6e --- /dev/null +++ b/cpukit/score/src/pheapgetblocksize.c @@ -0,0 +1,39 @@ +/** + * @file + * + * @ingroup ScoreProtHeap + * + * @brief Protected Heap Handler implementation. + */ + +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/protectedheap.h> + +bool _Protected_heap_Get_block_size( + Heap_Control *the_heap, + void *starting_address, + uintptr_t *size +) +{ + bool status; + + _RTEMS_Lock_allocator(); + status = _Heap_Size_of_alloc_area( the_heap, starting_address, size ); + _RTEMS_Unlock_allocator(); + return status; +} diff --git a/cpukit/score/src/pheapgetfreeinfo.c b/cpukit/score/src/pheapgetfreeinfo.c new file mode 100644 index 0000000000..e95bffe0ba --- /dev/null +++ b/cpukit/score/src/pheapgetfreeinfo.c @@ -0,0 +1,42 @@ +/** + * @file + * + * @ingroup ScoreProtHeap + * + * @brief Protected Heap Handler implementation. + */ + +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/protectedheap.h> + +bool _Protected_heap_Get_free_information( + Heap_Control *the_heap, + Heap_Information *info +) +{ + /* + * TBD: _Heap_Get_free_information does not error check or return status. + */ + + _RTEMS_Lock_allocator(); + _Heap_Get_free_information( the_heap, info ); + _RTEMS_Unlock_allocator(); + + return true; +} + diff --git a/cpukit/score/src/pheapgetinfo.c b/cpukit/score/src/pheapgetinfo.c new file mode 100644 index 0000000000..2c4a287edd --- /dev/null +++ b/cpukit/score/src/pheapgetinfo.c @@ -0,0 +1,43 @@ +/** + * @file + * + * @ingroup ScoreProtHeap + * + * @brief Protected Heap Handler implementation. + */ + +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/protectedheap.h> + +bool _Protected_heap_Get_information( + Heap_Control *the_heap, + Heap_Information_block *the_info +) +{ + if ( !the_heap ) + return false; + + if ( !the_info ) + return false; + + _RTEMS_Lock_allocator(); + _Heap_Get_information( the_heap, the_info ); + _RTEMS_Unlock_allocator(); + + return true; +} diff --git a/cpukit/score/src/pheapgetsize.c b/cpukit/score/src/pheapgetsize.c new file mode 100644 index 0000000000..fbf90ea3a4 --- /dev/null +++ b/cpukit/score/src/pheapgetsize.c @@ -0,0 +1,32 @@ +/** + * @file + * + * @ingroup ScoreProtHeap + * + * @brief Protected Heap Handler implementation. + */ + +/* + * COPYRIGHT (c) 1989-2009. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/protectedheap.h> + +uintptr_t _Protected_heap_Get_size( + Heap_Control *the_heap +) +{ + return _Heap_Get_size( the_heap ); +} diff --git a/cpukit/score/src/pheapinit.c b/cpukit/score/src/pheapinit.c new file mode 100644 index 0000000000..f2a11a7be9 --- /dev/null +++ b/cpukit/score/src/pheapinit.c @@ -0,0 +1,27 @@ +/** + * @file + * + * @ingroup ScoreProtHeap + * + * @brief Protected Heap Handler implementation. + */ + +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/protectedheap.h> + + diff --git a/cpukit/score/src/pheapresizeblock.c b/cpukit/score/src/pheapresizeblock.c new file mode 100644 index 0000000000..14dc522cff --- /dev/null +++ b/cpukit/score/src/pheapresizeblock.c @@ -0,0 +1,43 @@ +/** + * @file + * + * @ingroup ScoreProtHeap + * + * @brief Protected Heap Handler implementation. + */ + +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/protectedheap.h> + +bool _Protected_heap_Resize_block( + Heap_Control *the_heap, + void *starting_address, + uintptr_t size +) +{ + Heap_Resize_status status; + uintptr_t old_mem_size; + uintptr_t avail_mem_size; + + _RTEMS_Lock_allocator(); + status = _Heap_Resize_block( + the_heap, starting_address, size, &old_mem_size, &avail_mem_size ); + _RTEMS_Unlock_allocator(); + return (status == HEAP_RESIZE_SUCCESSFUL); +} + diff --git a/cpukit/score/src/pheapwalk.c b/cpukit/score/src/pheapwalk.c new file mode 100644 index 0000000000..4aa2279902 --- /dev/null +++ b/cpukit/score/src/pheapwalk.c @@ -0,0 +1,50 @@ +/** + * @file + * + * @ingroup ScoreProtHeap + * + * @brief Protected Heap Handler implementation. + */ + +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/protectedheap.h> + +bool _Protected_heap_Walk( + Heap_Control *the_heap, + int source, + bool do_dump +) +{ + bool status; + + /* + * If we are called from within a dispatching critical section, + * then it is forbidden to lock a mutex. But since we are inside + * a critical section, it should be safe to walk it unlocked. + * + * NOTE: Dispatching is also disabled during initialization. + */ + if ( !_Thread_Dispatch_disable_level ) { + _RTEMS_Lock_allocator(); + status = _Heap_Walk( the_heap, source, do_dump ); + _RTEMS_Unlock_allocator(); + } else { + status = _Heap_Walk( the_heap, source, do_dump ); + } + return status; +} diff --git a/cpukit/score/src/scheduler.c b/cpukit/score/src/scheduler.c new file mode 100644 index 0000000000..71938a728c --- /dev/null +++ b/cpukit/score/src/scheduler.c @@ -0,0 +1,25 @@ +/* + * Scheduler Handler / Initialization + * + * Copyright (C) 2010 Gedare Bloom. + * Copyright (C) 2011 On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/config.h> +#include <rtems/score/scheduler.h> + +void _Scheduler_Handler_initialization(void) +{ + (*_Scheduler.Operations.initialize)(); +} diff --git a/cpukit/score/src/schedulerpriority.c b/cpukit/score/src/schedulerpriority.c new file mode 100644 index 0000000000..279f42de6c --- /dev/null +++ b/cpukit/score/src/schedulerpriority.c @@ -0,0 +1,33 @@ +/* + * Scheduler Handler + * + * Copyright (C) 2010 Gedare Bloom. + * Copyright (C) 2011 On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/config.h> +#include <rtems/score/prioritybitmap.h> +#include <rtems/score/scheduler.h> +#include <rtems/score/schedulerpriority.h> + +/* Instantiate any global variables needed by the priority scheduler */ +volatile Priority_bit_map_Control _Priority_Major_bit_map; + +Priority_bit_map_Control _Priority_Bit_map[16] CPU_STRUCTURE_ALIGNMENT; + +void _Scheduler_priority_Initialize(void) +{ + _Scheduler_priority_Ready_queue_initialize(); + _Priority_bit_map_Handler_initialization(); +} diff --git a/cpukit/score/src/schedulerpriorityallocate.c b/cpukit/score/src/schedulerpriorityallocate.c new file mode 100644 index 0000000000..9df1e9ee5e --- /dev/null +++ b/cpukit/score/src/schedulerpriorityallocate.c @@ -0,0 +1,35 @@ +/* + * Scheduler Priority Handler / Allocate + * + * Copyright (C) 2010 Gedare Bloom. + * Copyright (C) 2011 On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/config.h> +#include <rtems/score/scheduler.h> +#include <rtems/score/schedulerpriority.h> +#include <rtems/score/wkspace.h> + +void* _Scheduler_priority_Allocate ( + Thread_Control *the_thread +) +{ + void *sched; + + sched = _Workspace_Allocate( sizeof(Scheduler_priority_Per_thread) ); + + the_thread->scheduler_info = (Scheduler_priority_Per_thread*) sched; + + return sched; +} diff --git a/cpukit/score/src/schedulerpriorityblock.c b/cpukit/score/src/schedulerpriorityblock.c new file mode 100644 index 0000000000..702ea48034 --- /dev/null +++ b/cpukit/score/src/schedulerpriorityblock.c @@ -0,0 +1,42 @@ +/* + * Scheduler Handler + * + * Copyright (C) 2010 Gedare Bloom. + * Copyright (C) 2011 On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/context.h> +#include <rtems/score/interr.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/priority.h> +#include <rtems/score/scheduler.h> +#include <rtems/score/schedulerpriority.h> +#include <rtems/score/thread.h> + +void _Scheduler_priority_Block( + Thread_Control *the_thread +) +{ + _Scheduler_priority_Ready_queue_extract( the_thread ); + + /* TODO: flash critical section? */ + + if ( _Thread_Is_heir( the_thread ) ) + _Scheduler_priority_Schedule_body(); + + if ( _Thread_Is_executing( the_thread ) ) + _Thread_Dispatch_necessary = true; + +} diff --git a/cpukit/score/src/schedulerpriorityenqueue.c b/cpukit/score/src/schedulerpriorityenqueue.c new file mode 100644 index 0000000000..82e192ac8c --- /dev/null +++ b/cpukit/score/src/schedulerpriorityenqueue.c @@ -0,0 +1,26 @@ +/* + * COPYRIGHT (c) 2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/config.h> +#include <rtems/score/scheduler.h> +#include <rtems/score/schedulerpriority.h> + +void _Scheduler_priority_Enqueue( + Thread_Control *the_thread +) +{ + _Scheduler_priority_Ready_queue_enqueue( the_thread ); +} diff --git a/cpukit/score/src/schedulerpriorityenqueuefirst.c b/cpukit/score/src/schedulerpriorityenqueuefirst.c new file mode 100644 index 0000000000..56573b7bb8 --- /dev/null +++ b/cpukit/score/src/schedulerpriorityenqueuefirst.c @@ -0,0 +1,27 @@ +/* + * COPYRIGHT (c) 2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/config.h> +#include <rtems/score/chain.h> +#include <rtems/score/schedulerpriority.h> + +void _Scheduler_priority_Enqueue_first( + Thread_Control *the_thread +) +{ + _Scheduler_priority_Ready_queue_enqueue_first( the_thread ); +} + diff --git a/cpukit/score/src/schedulerpriorityextract.c b/cpukit/score/src/schedulerpriorityextract.c new file mode 100644 index 0000000000..83f5d28f9f --- /dev/null +++ b/cpukit/score/src/schedulerpriorityextract.c @@ -0,0 +1,27 @@ +/* Scheduler Simple Handler / Extract + * + * COPYRIGHT (c) 2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/config.h> +#include <rtems/score/chain.h> +#include <rtems/score/schedulerpriority.h> + +void _Scheduler_priority_Extract( + Thread_Control *the_thread +) +{ + _Scheduler_priority_Ready_queue_extract( the_thread ); +} diff --git a/cpukit/score/src/schedulerpriorityfree.c b/cpukit/score/src/schedulerpriorityfree.c new file mode 100644 index 0000000000..27757755e3 --- /dev/null +++ b/cpukit/score/src/schedulerpriorityfree.c @@ -0,0 +1,29 @@ +/* + * Scheduler Handler + * + * Copyright (C) 2010 Gedare Bloom. + * Copyright (C) 2011 On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/config.h> +#include <rtems/score/scheduler.h> +#include <rtems/score/schedulerpriority.h> +#include <rtems/score/wkspace.h> + +void _Scheduler_priority_Free ( + Thread_Control *the_thread +) +{ + _Workspace_Free( the_thread->scheduler_info ); +} diff --git a/cpukit/score/src/schedulerpriorityschedule.c b/cpukit/score/src/schedulerpriorityschedule.c new file mode 100644 index 0000000000..e608e1f1f0 --- /dev/null +++ b/cpukit/score/src/schedulerpriorityschedule.c @@ -0,0 +1,25 @@ +/* + * Scheduler Handler / Scheduler + * + * Copyright (C) 2010 Gedare Bloom. + * Copyright (C) 2011 On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/scheduler.h> +#include <rtems/score/schedulerpriority.h> + +void _Scheduler_priority_Schedule(void) +{ + _Scheduler_priority_Schedule_body(); +} diff --git a/cpukit/score/src/schedulerpriorityunblock.c b/cpukit/score/src/schedulerpriorityunblock.c new file mode 100644 index 0000000000..8c0f490c8c --- /dev/null +++ b/cpukit/score/src/schedulerpriorityunblock.c @@ -0,0 +1,48 @@ +/* + * Scheduler Handler + * + * Copyright (C) 2010 Gedare Bloom. + * Copyright (C) 2011 On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/scheduler.h> +#include <rtems/score/schedulerpriority.h> + +void _Scheduler_priority_Unblock ( + Thread_Control *the_thread +) +{ + _Scheduler_priority_Ready_queue_enqueue(the_thread); + + /* TODO: flash critical section? */ + + /* + * If the thread that was unblocked is more important than the heir, + * then we have a new heir. This may or may not result in a + * context switch. + * + * Normal case: + * If the current thread is preemptible, then we need to do + * a context switch. + * Pseudo-ISR case: + * Even if the thread isn't preemptible, if the new heir is + * a pseudo-ISR system task, we need to do a context switch. + */ + if ( the_thread->current_priority < _Thread_Heir->current_priority ) { + _Thread_Heir = the_thread; + if ( _Thread_Executing->is_preemptible || + the_thread->current_priority == 0 ) + _Thread_Dispatch_necessary = true; + } +} diff --git a/cpukit/score/src/schedulerpriorityupdate.c b/cpukit/score/src/schedulerpriorityupdate.c new file mode 100644 index 0000000000..59b2432cf2 --- /dev/null +++ b/cpukit/score/src/schedulerpriorityupdate.c @@ -0,0 +1,42 @@ +/* + * Scheduler Handler + * + * Copyright (C) 2010 Gedare Bloom. + * Copyright (C) 2011 On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/config.h> +#include <rtems/score/priority.h> +#include <rtems/score/prioritybitmap.h> +#include <rtems/score/scheduler.h> +#include <rtems/score/schedulerpriority.h> +#include <rtems/score/thread.h> + +void _Scheduler_priority_Update( + Thread_Control *the_thread +) +{ + Scheduler_priority_Per_thread *sched_info; + Chain_Control *rq; + + sched_info = (Scheduler_priority_Per_thread *) the_thread->scheduler_info; + rq = (Chain_Control *) _Scheduler.information; + + sched_info->ready_chain = &rq[ the_thread->current_priority ]; + + _Priority_bit_map_Initialize_information( + &sched_info->Priority_map, + the_thread->current_priority + ); +} diff --git a/cpukit/score/src/schedulerpriorityyield.c b/cpukit/score/src/schedulerpriorityyield.c new file mode 100644 index 0000000000..ba46a08f3d --- /dev/null +++ b/cpukit/score/src/schedulerpriorityyield.c @@ -0,0 +1,55 @@ +/* + * Scheduler Priority Handler / Yield + * + * Copyright (C) 2010 Gedare Bloom. + * Copyright (C) 2011 On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/scheduler.h> +#include <rtems/score/schedulerpriority.h> +#include <rtems/score/thread.h> + +/* + * INTERRUPT LATENCY: + * ready chain + * select heir + */ + +void _Scheduler_priority_Yield(void) +{ + Scheduler_priority_Per_thread *sched_info; + ISR_Level level; + Thread_Control *executing; + Chain_Control *ready; + + executing = _Thread_Executing; + sched_info = (Scheduler_priority_Per_thread *) executing->scheduler_info; + ready = sched_info->ready_chain; + _ISR_Disable( level ); + if ( !_Chain_Has_only_one_node( ready ) ) { + _Chain_Extract_unprotected( &executing->Object.Node ); + _Chain_Append_unprotected( ready, &executing->Object.Node ); + + _ISR_Flash( level ); + + if ( _Thread_Is_heir( executing ) ) + _Thread_Heir = (Thread_Control *) _Chain_First( ready ); + _Thread_Dispatch_necessary = true; + } + else if ( !_Thread_Is_heir( executing ) ) + _Thread_Dispatch_necessary = true; + + _ISR_Enable( level ); +} diff --git a/cpukit/score/src/schedulersimple.c b/cpukit/score/src/schedulersimple.c new file mode 100644 index 0000000000..7a7ed944f4 --- /dev/null +++ b/cpukit/score/src/schedulersimple.c @@ -0,0 +1,84 @@ +/* + * Scheduler Simple Handler / Initialize + * Scheduler Simple Handler / Allocate (Empty Routine) + * Scheduler Simple Handler / Update (Empty Routine) + * Scheduler Simple Handler / Free (Empty Routine) + * + * COPYRIGHT (c) 2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/config.h> +#include <rtems/score/chain.h> +#include <rtems/score/scheduler.h> +#include <rtems/score/schedulersimple.h> +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> + +/** + * This routine does nothing, and is used as a stub for Schedule allocate + * + * Note: returns a non-zero value, or else thread initialize thinks the + * allocation failed. + * + * The overhead of a function call will still be imposed. + */ +void * _Scheduler_simple_Allocate( + Thread_Control *the_thread +) +{ + return (void*)-1; /* maybe pick an appropriate poison value */ +} + + +/** + * This routine does nothing, and is used as a stub for Schedule update + * + * The overhead of a function call will still be imposed. + */ +void _Scheduler_simple_Update( + Thread_Control *the_thread +) +{ +} + +/** + * This routine does nothing, and is used as a stub for Schedule free + * + * The overhead of a function call will still be imposed. + */ +void _Scheduler_simple_Free( + Thread_Control *the_thread +) +{ +} + +/** + * This routine initializes the simple scheduler. + */ +void _Scheduler_simple_Initialize ( void ) +{ + void *f; + + /* + * Initialize Ready Queue + */ + + /* allocate ready queue structures */ + f = _Workspace_Allocate_or_fatal_error( sizeof(Chain_Control) ); + _Scheduler.information = f; + + /* initialize ready queue structure */ + _Chain_Initialize_empty( (Chain_Control *)f ); +} diff --git a/cpukit/score/src/schedulersimpleblock.c b/cpukit/score/src/schedulersimpleblock.c new file mode 100644 index 0000000000..212f4f10bf --- /dev/null +++ b/cpukit/score/src/schedulersimpleblock.c @@ -0,0 +1,39 @@ +/* + * Scheduler Simple Handler / Block + * + * COPYRIGHT (c) 2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/context.h> +#include <rtems/score/interr.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/priority.h> +#include <rtems/score/scheduler.h> +#include <rtems/score/thread.h> +#include <rtems/score/schedulersimple.h> + +void _Scheduler_simple_Block( + Thread_Control *the_thread +) +{ + _Scheduler_simple_Extract(the_thread); + + if ( _Thread_Is_heir( the_thread ) ) + _Scheduler_simple_Schedule(); + + if ( _Thread_Is_executing( the_thread ) ) + _Thread_Dispatch_necessary = true; +} diff --git a/cpukit/score/src/schedulersimpleenqueue.c b/cpukit/score/src/schedulersimpleenqueue.c new file mode 100644 index 0000000000..8e5e6381c5 --- /dev/null +++ b/cpukit/score/src/schedulersimpleenqueue.c @@ -0,0 +1,29 @@ +/* + * Schedule Simple Handler / Enqueue + * + * COPYRIGHT (c) 2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/schedulersimple.h> + +void _Scheduler_simple_Enqueue( + Thread_Control *the_thread +) +{ + _Scheduler_simple_Ready_queue_Enqueue( the_thread ); +} diff --git a/cpukit/score/src/schedulersimpleenqueuefirst.c b/cpukit/score/src/schedulersimpleenqueuefirst.c new file mode 100644 index 0000000000..d6fd7dda98 --- /dev/null +++ b/cpukit/score/src/schedulersimpleenqueuefirst.c @@ -0,0 +1,28 @@ +/* + * Schedule Simple Handler / Enqueue First + * + * COPYRIGHT (c) 2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/thread.h> +#include <rtems/score/schedulersimple.h> + +void _Scheduler_simple_Enqueue_first( + Thread_Control *the_thread +) +{ + _Scheduler_simple_Ready_queue_Enqueue_first( the_thread ); +} diff --git a/cpukit/score/src/schedulersimpleextract.c b/cpukit/score/src/schedulersimpleextract.c new file mode 100644 index 0000000000..208fcb55bd --- /dev/null +++ b/cpukit/score/src/schedulersimpleextract.c @@ -0,0 +1,28 @@ +/* + * Schedule Simple Handler / Extract + * + * COPYRIGHT (c) 2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/thread.h> +#include <rtems/score/schedulersimple.h> + +void _Scheduler_simple_Extract( + Thread_Control *the_thread +) +{ + _Chain_Extract_unprotected( &the_thread->Object.Node ); +} diff --git a/cpukit/score/src/schedulersimplereadyqueueenqueue.c b/cpukit/score/src/schedulersimplereadyqueueenqueue.c new file mode 100644 index 0000000000..788f94b20b --- /dev/null +++ b/cpukit/score/src/schedulersimplereadyqueueenqueue.c @@ -0,0 +1,48 @@ +/* + * Schedule Simple Handler / Ready Queue Enqueue + * + * COPYRIGHT (c) 2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/schedulersimple.h> + +void _Scheduler_simple_Ready_queue_Enqueue( + Thread_Control *the_thread +) +{ + Chain_Control *ready; + Chain_Node *the_node; + Thread_Control *current; + + ready = (Chain_Control *)_Scheduler.information; + the_node = _Chain_First( ready ); + current = (Thread_Control *)ready; + + for ( ; !_Chain_Is_tail( ready, the_node ) ; the_node = the_node->next ) { + current = (Thread_Control *) the_node; + + /* break when AT END OR PAST our priority */ + if ( the_thread->current_priority < current->current_priority ) { + current = (Thread_Control *)current->Object.Node.previous; + break; + } + } + + /* enqueue */ + _Chain_Insert_unprotected( (Chain_Node *)current, &the_thread->Object.Node ); +} diff --git a/cpukit/score/src/schedulersimplereadyqueueenqueuefirst.c b/cpukit/score/src/schedulersimplereadyqueueenqueuefirst.c new file mode 100644 index 0000000000..dee0bbd116 --- /dev/null +++ b/cpukit/score/src/schedulersimplereadyqueueenqueuefirst.c @@ -0,0 +1,52 @@ +/* + * Schedule Simple Handler / Ready Queue Enqueue First + * + * COPYRIGHT (c) 2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/thread.h> +#include <rtems/score/schedulersimple.h> + +void _Scheduler_simple_Ready_queue_Enqueue_first( + Thread_Control *the_thread +) +{ + Chain_Control *ready; + Chain_Node *the_node; + Thread_Control *current; + + ready = (Chain_Control *)_Scheduler.information; + current = (Thread_Control *)ready; + + /* + * Do NOT need to check for end of chain because there is always + * at least one task on the ready chain -- the IDLE task. It can + * never block, should never attempt to obtain a semaphore or mutex, + * and thus will always be there. + */ + for ( the_node = _Chain_First(ready) ; ; the_node = the_node->next ) { + current = (Thread_Control *) the_node; + + /* break when AT HEAD OF (or PAST) our priority */ + if ( the_thread->current_priority <= current->current_priority ) { + current = (Thread_Control *)current->Object.Node.previous; + break; + } + } + + /* enqueue */ + _Chain_Insert_unprotected( (Chain_Node *)current, &the_thread->Object.Node ); +} diff --git a/cpukit/score/src/schedulersimpleschedule.c b/cpukit/score/src/schedulersimpleschedule.c new file mode 100644 index 0000000000..354e61f705 --- /dev/null +++ b/cpukit/score/src/schedulersimpleschedule.c @@ -0,0 +1,34 @@ +/* + * Scheduler Simple Handler / Schedule + * + * COPYRIGHT (c) 2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/context.h> +#include <rtems/score/interr.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/priority.h> +#include <rtems/score/percpu.h> +#include <rtems/score/scheduler.h> +#include <rtems/score/thread.h> +#include <rtems/score/schedulersimple.h> + +void _Scheduler_simple_Schedule(void) +{ + _Thread_Heir = (Thread_Control *) _Chain_First( + (Chain_Control *) _Scheduler.information + ); +} diff --git a/cpukit/score/src/schedulersimpleunblock.c b/cpukit/score/src/schedulersimpleunblock.c new file mode 100644 index 0000000000..5be5c16ad9 --- /dev/null +++ b/cpukit/score/src/schedulersimpleunblock.c @@ -0,0 +1,47 @@ +/* + * Scheduler Simple Handler / Unblock + * + * COPYRIGHT (c) 2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/schedulersimple.h> +#include <rtems/score/thread.h> + +void _Scheduler_simple_Unblock( + Thread_Control *the_thread +) +{ + _Scheduler_simple_Ready_queue_Enqueue(the_thread); + + /* + * If the thread that was unblocked is more important than the heir, + * then we have a new heir. This may or may not result in a + * context switch. + * + * Normal case: + * If the current thread is preemptible, then we need to do + * a context switch. + * Pseudo-ISR case: + * Even if the thread isn't preemptible, if the new heir is + * a pseudo-ISR system task, we need to do a context switch. + */ + if ( the_thread->current_priority < _Thread_Heir->current_priority ) { + _Thread_Heir = the_thread; + if ( _Thread_Executing->is_preemptible || + the_thread->current_priority == 0 ) + _Thread_Dispatch_necessary = true; + } +} diff --git a/cpukit/score/src/schedulersimpleyield.c b/cpukit/score/src/schedulersimpleyield.c new file mode 100644 index 0000000000..61e80db7e2 --- /dev/null +++ b/cpukit/score/src/schedulersimpleyield.c @@ -0,0 +1,42 @@ +/* + * Scheduler Simple Handler / Yield + * + * COPYRIGHT (c) 2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/scheduler.h> +#include <rtems/score/thread.h> +#include <rtems/score/schedulersimple.h> + +void _Scheduler_simple_Yield( void ) +{ + ISR_Level level; + Thread_Control *executing; + + executing = _Thread_Executing; + _ISR_Disable( level ); + + _Scheduler_simple_Ready_queue_Requeue(&_Scheduler, executing); + + _ISR_Flash( level ); + + _Scheduler_simple_Schedule(); + + if ( !_Thread_Is_heir( executing ) ) + _Thread_Dispatch_necessary = true; + + _ISR_Enable( level ); +} diff --git a/cpukit/score/src/smp.c b/cpukit/score/src/smp.c new file mode 100644 index 0000000000..4a0c13947f --- /dev/null +++ b/cpukit/score/src/smp.c @@ -0,0 +1,153 @@ +/* + * COPYRIGHT (c) 1989-2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/bspsmp.h> +#include <rtems/score/thread.h> + +#if defined(RTEMS_SMP) +#define SMP_DEBUG + +#if defined(SMP_DEBUG) + #include <rtems/bspIo.h> +#endif + +void rtems_smp_run_first_task(int cpu) +{ + Thread_Control *heir; + + /* + * This CPU has an heir thread so we need to dispatch it. + */ + heir = _Thread_Heir; + + /* + * This is definitely a hack until we have SMP scheduling. Since there + * is only one executing and heir right now, we have to fake this out. + */ + _Thread_Dispatch_disable_level = 1; + _Thread_Executing = heir; + _CPU_Context_switch_to_first_task_smp( &heir->Registers ); +} + +void rtems_smp_secondary_cpu_initialize(void) +{ + int cpu; + + cpu = bsp_smp_processor_id(); + + bsp_smp_secondary_cpu_initialize(cpu); + + #if defined(SMP_DEBUG) + printk( "Made it to %d -- ", cpu ); + #endif + + /* + * Inform the primary CPU that this secondary CPU is initialized + * and ready to dispatch to the first thread it is supposed to + * execute when the primary CPU is ready. + */ + _Per_CPU_Information[cpu].state = RTEMS_BSP_SMP_CPU_INITIALIZED; + + /* + * HACK: Should not have to enable interrupts in real system here. + * It should happen as part of switching to the first task. + */ + + _Per_CPU_Information[cpu].isr_nest_level = 1; + _ISR_Set_level( 0 ); + while(1) ; +} + +void rtems_smp_process_interrupt(void) +{ + int cpu; + uint32_t message; + ISR_Level level; + + cpu = bsp_smp_processor_id(); + + level = _SMP_lock_Spinlock_Obtain( &_Per_CPU_Information[cpu].lock ); + message = _Per_CPU_Information[cpu].message; + _Per_CPU_Information[cpu].message &= ~message; + _SMP_lock_Spinlock_Release( &_Per_CPU_Information[cpu].lock, level ); + + #if defined(SMP_DEBUG) + { + void *sp = __builtin_frame_address(0); + if ( !(message & RTEMS_BSP_SMP_SHUTDOWN) ) + printk( "ISR on CPU %d -- (0x%02x) (0x%p)\n", cpu, message, sp ); + printk( "Dispatch level %d\n", _Thread_Dispatch_disable_level ); + } + #endif + + if ( message & RTEMS_BSP_SMP_FIRST_TASK ) { + _Per_CPU_Information[cpu].isr_nest_level = 0; + _Per_CPU_Information[cpu].message = 0; + _Per_CPU_Information[cpu].state = RTEMS_BSP_SMP_CPU_INITIALIZED; + rtems_smp_run_first_task(cpu); + /* does not return */ + } + + if ( message & RTEMS_BSP_SMP_SHUTDOWN ) { + ISR_Level level; + _Thread_Dispatch_disable_level = 0; + _Per_CPU_Information[cpu].isr_nest_level = 0; + _Per_CPU_Information[cpu].state = RTEMS_BSP_SMP_CPU_SHUTDOWN; + _ISR_Disable( level ); + while(1) + ; + /* does not continue past here */ + } + + if ( message & RTEMS_BSP_SMP_CONTEXT_SWITCH_NECESSARY ) { + printk( "switch needed\n" ); + _Per_CPU_Information[cpu].dispatch_necessary = true; + } +} + +void rtems_smp_send_message( + int cpu, + uint32_t message +) +{ + ISR_Level level; + + level = _SMP_lock_Spinlock_Obtain( &_Per_CPU_Information[cpu].lock ); + _Per_CPU_Information[cpu].message |= message; + _SMP_lock_Spinlock_Release( &_Per_CPU_Information[cpu].lock, level ); + bsp_smp_interrupt_cpu( cpu ); +} + +void rtems_smp_broadcast_message( + uint32_t message +) +{ + int dest_cpu; + int cpu; + ISR_Level level; + + cpu = bsp_smp_processor_id(); + + for ( dest_cpu=0 ; dest_cpu < _SMP_Processor_count; dest_cpu++ ) { + if ( cpu == dest_cpu ) + continue; + level = _SMP_lock_Spinlock_Obtain( &_Per_CPU_Information[cpu].lock ); + _Per_CPU_Information[dest_cpu].message |= message; + _SMP_lock_Spinlock_Release( &_Per_CPU_Information[cpu].lock, level ); + } + bsp_smp_broadcast_interrupt(); +} +#endif diff --git a/cpukit/score/src/smplock.c b/cpukit/score/src/smplock.c new file mode 100644 index 0000000000..1dd691835b --- /dev/null +++ b/cpukit/score/src/smplock.c @@ -0,0 +1,49 @@ +/* + * COPYRIGHT (c) 1989-2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/smplock.h> + +void _SMP_lock_Spinlock_Initialize( + SMP_lock_Control *lock +) +{ + *lock = 0; +} + +ISR_Level _SMP_lock_Spinlock_Obtain( + SMP_lock_Control *lock +) +{ + ISR_Level level; + uint32_t value = 1; + uint32_t previous; + + /* Note: Disable provides an implicit memory barrier. */ + _ISR_Disable( level ); + do { + SMP_CPU_SWAP( lock, value, previous ); + } while (previous == 1); + return level; +} + +void _SMP_lock_Spinlock_Release( + SMP_lock_Control *lock, + ISR_Level level +) +{ + *lock = 0; + _ISR_Enable( level ); +} diff --git a/cpukit/score/src/thread.c b/cpukit/score/src/thread.c new file mode 100644 index 0000000000..7a0eb38502 --- /dev/null +++ b/cpukit/score/src/thread.c @@ -0,0 +1,123 @@ +/* + * Thread Handler + * + * + * COPYRIGHT (c) 1989-2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/config.h> +#include <rtems/score/apiext.h> +#include <rtems/score/context.h> +#include <rtems/score/interr.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/priority.h> +#include <rtems/score/scheduler.h> +#include <rtems/score/states.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/userext.h> +#include <rtems/score/wkspace.h> +#include <rtems/config.h> + +#if defined(RTEMS_SMP) + #include <rtems/bspsmp.h> +#endif + +/* + * _Thread_Handler_initialization + * + * This routine initializes all thread manager related data structures. + * + * Input parameters: NONE + * + * Output parameters: NONE + */ + +void _Thread_Handler_initialization(void) +{ + uint32_t ticks_per_timeslice; + uint32_t maximum_extensions; + uint32_t maximum_internal_threads; + #if defined(RTEMS_MULTIPROCESSING) + uint32_t maximum_proxies; + #endif + + ticks_per_timeslice = Configuration.ticks_per_timeslice; + maximum_extensions = Configuration.maximum_extensions; + #if defined(RTEMS_MULTIPROCESSING) + maximum_proxies = _Configuration_MP_table->maximum_proxies; + #endif + /* + * BOTH stacks hooks must be set or both must be NULL. + * Do not allow mixture. + */ + if ( !( (!Configuration.stack_allocate_hook) + == (!Configuration.stack_free_hook) ) ) + _Internal_error_Occurred( + INTERNAL_ERROR_CORE, + true, + INTERNAL_ERROR_BAD_STACK_HOOK + ); + + _Thread_Dispatch_necessary = false; + _Thread_Executing = NULL; + _Thread_Heir = NULL; +#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) + _Thread_Allocated_fp = NULL; +#endif + + _Thread_Maximum_extensions = maximum_extensions; + + _Thread_Ticks_per_timeslice = ticks_per_timeslice; + + #if defined(RTEMS_MULTIPROCESSING) + _Thread_MP_Handler_initialization( maximum_proxies ); + #endif + + /* + * Initialize the internal class of threads. We need an IDLE thread + * per CPU in an SMP system. In addition, if this is a loosely + * coupled multiprocessing system, account for the MPCI Server Thread. + */ + #if defined(RTEMS_SMP) + maximum_internal_threads = rtems_smp_maximum_processors; + #else + maximum_internal_threads = 1; + #endif + + #if defined(RTEMS_MULTIPROCESSING) + if ( _System_state_Is_multiprocessing ) + maximum_internal_threads += 1; + #endif + + _Objects_Initialize_information( + &_Thread_Internal_information, + OBJECTS_INTERNAL_API, + OBJECTS_INTERNAL_THREADS, + maximum_internal_threads, + sizeof( Thread_Control ), + /* size of this object's control block */ + false, /* true if names for this object are strings */ + 8 /* maximum length of each object's name */ + #if defined(RTEMS_MULTIPROCESSING) + , + false, /* true if this is a global object class */ + NULL /* Proxy extraction support callout */ + #endif + ); + +} diff --git a/cpukit/score/src/threadblockingoperationcancel.c b/cpukit/score/src/threadblockingoperationcancel.c new file mode 100644 index 0000000000..354df0c7e9 --- /dev/null +++ b/cpukit/score/src/threadblockingoperationcancel.c @@ -0,0 +1,89 @@ +/* + * Cancel Thread Blocking Operation + * + * + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/thread.h> +#if defined(RTEMS_DEBUG) +#include <rtems/score/interr.h> +#endif + +void _Thread_blocking_operation_Cancel( +#if defined(RTEMS_DEBUG) + Thread_blocking_operation_States sync_state, +#else + Thread_blocking_operation_States sync_state __attribute__((unused)), +#endif + Thread_Control *the_thread, + ISR_Level level +) +{ + /* + * Cases that should not happen and why. + * + * THREAD_BLOCKING_OPERATION_SYNCHRONIZED: + * + * This indicates that someone did not enter a blocking + * operation critical section. + * + * THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED: + * + * This indicates that there was nothing to cancel so + * we should not have been called. + */ + + #if defined(RTEMS_DEBUG) + if ( (sync_state == THREAD_BLOCKING_OPERATION_SYNCHRONIZED) || + (sync_state == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED) ) { + _Internal_error_Occurred( + INTERNAL_ERROR_CORE, + true, + INTERNAL_ERROR_IMPLEMENTATION_BLOCKING_OPERATION_CANCEL + ); + } + #endif + + /* + * The thread is not waiting on anything after this completes. + */ + the_thread->Wait.queue = NULL; + + /* + * If the sync state is timed out, this is very likely not needed. + * But better safe than sorry when it comes to critical sections. + */ + 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 ); + + /* + * 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 + +} diff --git a/cpukit/score/src/threadchangepriority.c b/cpukit/score/src/threadchangepriority.c new file mode 100644 index 0000000000..95011d8237 --- /dev/null +++ b/cpukit/score/src/threadchangepriority.c @@ -0,0 +1,99 @@ +/* + * Thread Handler / Change Priority + * + * COPYRIGHT (c) 1989-2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/scheduler.h> +#include <rtems/score/schedulerpriority.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> + +void _Thread_Change_priority( + Thread_Control *the_thread, + Priority_Control new_priority, + bool prepend_it +) +{ + ISR_Level level; + States_Control state, original_state; + + /* + * Save original state + */ + original_state = the_thread->current_state; + + /* + * Set a transient state for the thread so it is pulled off the Ready chains. + * This will prevent it from being scheduled no matter what happens in an + * ISR. + */ + _Thread_Set_transient( the_thread ); + + /* + * Do not bother recomputing all the priority related information if + * we are not REALLY changing priority. + */ + if ( the_thread->current_priority != new_priority ) + _Thread_Set_priority( the_thread, new_priority ); + + _ISR_Disable( level ); + + /* + * If the thread has more than STATES_TRANSIENT set, then it is blocked, + * If it is blocked on a thread queue, then we need to requeue it. + */ + state = the_thread->current_state; + if ( state != STATES_TRANSIENT ) { + /* Only clear the transient state if it wasn't set already */ + if ( ! _States_Is_transient( original_state ) ) + the_thread->current_state = _States_Clear( STATES_TRANSIENT, state ); + _ISR_Enable( level ); + if ( _States_Is_waiting_on_thread_queue( state ) ) { + _Thread_queue_Requeue( the_thread->Wait.queue, the_thread ); + } + return; + } + + /* Only clear the transient state if it wasn't set already */ + if ( ! _States_Is_transient( original_state ) ) { + /* + * Interrupts are STILL disabled. + * We now know the thread will be in the READY state when we remove + * the TRANSIENT state. So we have to place it on the appropriate + * Ready Queue with interrupts off. + */ + the_thread->current_state = _States_Clear( STATES_TRANSIENT, state ); + + if ( prepend_it ) + _Scheduler_Enqueue_first( the_thread ); + else + _Scheduler_Enqueue( the_thread ); + } + + _ISR_Flash( level ); + + /* + * We altered the set of thread priorities. So let's figure out + * who is the heir and if we need to switch to them. + */ + _Scheduler_Schedule(); + + if ( !_Thread_Is_executing_also_the_heir() && + _Thread_Executing->is_preemptible ) + _Thread_Dispatch_necessary = true; + _ISR_Enable( level ); +} diff --git a/cpukit/score/src/threadclearstate.c b/cpukit/score/src/threadclearstate.c new file mode 100644 index 0000000000..afeab04e8e --- /dev/null +++ b/cpukit/score/src/threadclearstate.c @@ -0,0 +1,58 @@ +/* + * Thread Handler / Thread Clear State + * + * COPYRIGHT (c) 1989-2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/apiext.h> +#include <rtems/score/context.h> +#include <rtems/score/interr.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/priority.h> +#include <rtems/score/scheduler.h> +#include <rtems/score/states.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/userext.h> +#include <rtems/score/wkspace.h> + +/* + * INTERRUPT LATENCY: + * priority map + * select heir + */ +void _Thread_Clear_state( + Thread_Control *the_thread, + States_Control state +) +{ + ISR_Level level; + States_Control current_state; + + _ISR_Disable( level ); + current_state = the_thread->current_state; + + if ( current_state & state ) { + current_state = + the_thread->current_state = _States_Clear( state, current_state ); + + if ( _States_Is_ready( current_state ) ) { + _Scheduler_Unblock( the_thread ); + } + } + _ISR_Enable( level ); +} diff --git a/cpukit/score/src/threadclose.c b/cpukit/score/src/threadclose.c new file mode 100644 index 0000000000..ea2ee5bda4 --- /dev/null +++ b/cpukit/score/src/threadclose.c @@ -0,0 +1,104 @@ +/* + * Thread Handler / Thread Close + * + * COPYRIGHT (c) 1989-2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/apiext.h> +#include <rtems/score/context.h> +#include <rtems/score/interr.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/priority.h> +#include <rtems/score/scheduler.h> +#include <rtems/score/states.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/userext.h> +#include <rtems/score/wkspace.h> + +void _Thread_Close( + Objects_Information *information, + Thread_Control *the_thread +) +{ + /* + * Now we are in a dispatching critical section again and we + * can take the thread OUT of the published set. It is invalid + * to use this thread's Id after this call. This will prevent + * any other task from attempting to initiate a call on this task. + */ + _Objects_Invalidate_Id( information, &the_thread->Object ); + + /* + * We assume the Allocator Mutex is locked when we get here. + * This provides sufficient protection to let the user extensions + * run but as soon as we get back, we will make the thread + * disappear and set a transient state on it. So we temporarily + * unnest dispatching. + */ + _Thread_Unnest_dispatch(); + + _User_extensions_Thread_delete( the_thread ); + + _Thread_Disable_dispatch(); + + /* + * Now we are in a dispatching critical section again and we + * can take the thread OUT of the published set. It is invalid + * to use this thread's Id OR name after this call. + */ + _Objects_Close( information, &the_thread->Object ); + + /* + * By setting the dormant state, the thread will not be considered + * for scheduling when we remove any blocking states. + */ + _Thread_Set_state( the_thread, STATES_DORMANT ); + + if ( !_Thread_queue_Extract_with_proxy( the_thread ) ) { + if ( _Watchdog_Is_active( &the_thread->Timer ) ) + (void) _Watchdog_Remove( &the_thread->Timer ); + } + + /* + * Free the per-thread scheduling information. + */ + _Scheduler_Free( the_thread ); + + /* + * The thread might have been FP. So deal with that. + */ +#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) +#if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE ) + if ( _Thread_Is_allocated_fp( the_thread ) ) + _Thread_Deallocate_fp(); +#endif + the_thread->fp_context = NULL; + + _Workspace_Free( the_thread->Start.fp_context ); +#endif + + /* + * Free the rest of the memory associated with this task + * and set the associated pointers to NULL for safety. + */ + _Thread_Stack_Free( the_thread ); + the_thread->Start.stack = NULL; + + _Workspace_Free( the_thread->extensions ); + the_thread->extensions = NULL; +} diff --git a/cpukit/score/src/threadcreateidle.c b/cpukit/score/src/threadcreateidle.c new file mode 100644 index 0000000000..6a4bf65e9c --- /dev/null +++ b/cpukit/score/src/threadcreateidle.c @@ -0,0 +1,106 @@ +/* + * Thread Handler + * + * + * COPYRIGHT (c) 1989-2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/apiext.h> +#include <rtems/score/context.h> +#include <rtems/score/interr.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/priority.h> +#include <rtems/score/states.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/userext.h> +#include <rtems/score/wkspace.h> +#include <rtems/config.h> +#include <rtems/bspsmp.h> + +static inline void _Thread_Create_idle_helper( + uint32_t name_u32, + int cpu +) +{ + Objects_Name name; + Thread_Control *idle; + + name.name_u32 = name_u32; + + /* + * The entire workspace is zeroed during its initialization. Thus, all + * fields not explicitly assigned were explicitly zeroed by + * _Workspace_Initialization. + */ + idle = _Thread_Internal_allocate(); + + /* + * This is only called during initialization and we better be sure + * that when _Thread_Initialize unnests dispatch that we do not + * do anything stupid. + */ + _Thread_Disable_dispatch(); + + _Thread_Initialize( + &_Thread_Internal_information, + idle, + NULL, /* allocate the stack */ + _Stack_Ensure_minimum( Configuration.idle_task_stack_size ), + CPU_IDLE_TASK_IS_FP, + PRIORITY_MAXIMUM, + true, /* preemptable */ + THREAD_CPU_BUDGET_ALGORITHM_NONE, + NULL, /* no budget algorithm callout */ + 0, /* all interrupts enabled */ + name + ); + + _Thread_Unnest_dispatch(); + + /* + * WARNING!!! This is necessary to "kick" start the system and + * MUST be done before _Thread_Start is invoked. + */ + _Per_CPU_Information[ cpu ].idle = + _Per_CPU_Information[ cpu ].heir = + _Per_CPU_Information[ cpu ].executing = idle; + + _Thread_Start( + idle, + THREAD_START_NUMERIC, + Configuration.idle_task, + NULL, + 0 + ); +} + +void _Thread_Create_idle( void ) +{ + #if defined(RTEMS_SMP) + int cpu; + + for ( cpu=0 ; cpu < _SMP_Processor_count ; cpu++ ) { + _Thread_Create_idle_helper( + _Objects_Build_name( 'I', 'D', 'L', 'E' ), + cpu + ); + } + #else + _Thread_Create_idle_helper(_Objects_Build_name( 'I', 'D', 'L', 'E' ), 0); + #endif +} diff --git a/cpukit/score/src/threaddelayended.c b/cpukit/score/src/threaddelayended.c new file mode 100644 index 0000000000..4f72764608 --- /dev/null +++ b/cpukit/score/src/threaddelayended.c @@ -0,0 +1,71 @@ +/* + * Thread Handler + * + * + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/apiext.h> +#include <rtems/score/context.h> +#include <rtems/score/interr.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/priority.h> +#include <rtems/score/states.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/userext.h> +#include <rtems/score/wkspace.h> + +/*PAGE + * + * _Thread_Delay_ended + * + * This routine processes a thread whose delay period has ended. + * It is called by the watchdog handler. + * + * Input parameters: + * id - thread id + * + * Output parameters: NONE + */ + +void _Thread_Delay_ended( + Objects_Id id, + void *ignored __attribute__((unused)) +) +{ + Thread_Control *the_thread; + Objects_Locations location; + + the_thread = _Thread_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: +#if defined(RTEMS_MULTIPROCESSING) + case OBJECTS_REMOTE: /* impossible */ +#endif + break; + case OBJECTS_LOCAL: + _Thread_Clear_state( + the_thread, + STATES_DELAYING + | STATES_WAITING_FOR_TIME + | STATES_INTERRUPTIBLE_BY_SIGNAL + ); + _Thread_Unnest_dispatch(); + break; + } +} diff --git a/cpukit/score/src/threaddispatch.c b/cpukit/score/src/threaddispatch.c new file mode 100644 index 0000000000..5e0828e2a6 --- /dev/null +++ b/cpukit/score/src/threaddispatch.c @@ -0,0 +1,193 @@ +/* + * Thread Handler + * + * + * COPYRIGHT (c) 1989-2009. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/apiext.h> +#include <rtems/score/context.h> +#include <rtems/score/interr.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/priority.h> +#include <rtems/score/states.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/userext.h> +#include <rtems/score/wkspace.h> + +#ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__ + #include <rtems/score/timestamp.h> +#endif + +/*PAGE + * + * _Thread_Enable_dispatch + * + * This kernel routine exits a context switch disable critical section. + * This is the NOT INLINED version. + * + * Input parameters: NONE + * + * Output parameters: NONE + * + * INTERRUPT LATENCY: + * dispatch thread + * no dispatch thread + */ + +#if ( (defined(CPU_INLINE_ENABLE_DISPATCH) && \ + (CPU_INLINE_ENABLE_DISPATCH == FALSE)) || \ + (__RTEMS_DO_NOT_INLINE_THREAD_ENABLE_DISPATCH__ == 1) ) +void _Thread_Enable_dispatch( void ) +{ + if ( --_Thread_Dispatch_disable_level ) + return; + _Thread_Dispatch(); +} +#endif + +/*PAGE + * + * _Thread_Dispatch + * + * This kernel routine determines if a dispatch is needed, and if so + * dispatches to the heir thread. Once the heir is running an attempt + * is made to dispatch any ASRs. + * + * ALTERNATE ENTRY POINTS: + * void _Thread_Enable_dispatch(); + * + * Input parameters: NONE + * + * Output parameters: NONE + * + * INTERRUPT LATENCY: + * dispatch thread + * no dispatch thread + */ + +void _Thread_Dispatch( void ) +{ + Thread_Control *executing; + Thread_Control *heir; + ISR_Level level; + + executing = _Thread_Executing; + _ISR_Disable( level ); + while ( _Thread_Dispatch_necessary == true ) { + heir = _Thread_Heir; + _Thread_Dispatch_disable_level = 1; + _Thread_Dispatch_necessary = false; + _Thread_Executing = heir; + + /* + * When the heir and executing are the same, then we are being + * requested to do the post switch dispatching. This is normally + * done to dispatch signals. + */ + if ( heir == executing ) + goto post_switch; + + /* + * Since heir and executing are not the same, we need to do a real + * context switch. + */ +#if __RTEMS_ADA__ + executing->rtems_ada_self = rtems_ada_self; + rtems_ada_self = heir->rtems_ada_self; +#endif + if ( heir->budget_algorithm == THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE ) + heir->cpu_time_budget = _Thread_Ticks_per_timeslice; + + _ISR_Enable( level ); + + #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__ + { + Timestamp_Control uptime, ran; + _TOD_Get_uptime( &uptime ); + _Timestamp_Subtract( + &_Thread_Time_of_last_context_switch, + &uptime, + &ran + ); + _Timestamp_Add_to( &executing->cpu_time_used, &ran ); + _Thread_Time_of_last_context_switch = uptime; + } + #else + heir->cpu_time_used++; + #endif + + /* + * Switch libc's task specific data. + */ + if ( _Thread_libc_reent ) { + executing->libc_reent = *_Thread_libc_reent; + *_Thread_libc_reent = heir->libc_reent; + } + + _User_extensions_Thread_switch( executing, heir ); + + /* + * If the CPU has hardware floating point, then we must address saving + * and restoring it as part of the context switch. + * + * The second conditional compilation section selects the algorithm used + * to context switch between floating point tasks. The deferred algorithm + * can be significantly better in a system with few floating point tasks + * because it reduces the total number of save and restore FP context + * operations. However, this algorithm can not be used on all CPUs due + * to unpredictable use of FP registers by some compilers for integer + * operations. + */ + +#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) +#if ( CPU_USE_DEFERRED_FP_SWITCH != TRUE ) + if ( executing->fp_context != NULL ) + _Context_Save_fp( &executing->fp_context ); +#endif +#endif + + _Context_Switch( &executing->Registers, &heir->Registers ); + +#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) +#if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE ) + if ( (executing->fp_context != NULL) && + !_Thread_Is_allocated_fp( executing ) ) { + if ( _Thread_Allocated_fp != NULL ) + _Context_Save_fp( &_Thread_Allocated_fp->fp_context ); + _Context_Restore_fp( &executing->fp_context ); + _Thread_Allocated_fp = executing; + } +#else + if ( executing->fp_context != NULL ) + _Context_Restore_fp( &executing->fp_context ); +#endif +#endif + + executing = _Thread_Executing; + + _ISR_Disable( level ); + } + +post_switch: + _Thread_Dispatch_disable_level = 0; + + _ISR_Enable( level ); + + _API_extensions_Run_postswitch(); +} diff --git a/cpukit/score/src/threadget.c b/cpukit/score/src/threadget.c new file mode 100644 index 0000000000..30574a3617 --- /dev/null +++ b/cpukit/score/src/threadget.c @@ -0,0 +1,100 @@ +/* + * Thread Handler - Object Id to Thread Pointer + * + * COPYRIGHT (c) 1989-2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/apiext.h> +#include <rtems/score/context.h> +#include <rtems/score/interr.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/priority.h> +#include <rtems/score/states.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> + + +/** + * This function maps thread IDs to thread control + * blocks. If ID corresponds to a local thread, then it + * returns the_thread control pointer which maps to ID + * and location is set to OBJECTS_LOCAL. If the thread ID is + * global and resides on a remote node, then location is set + * to OBJECTS_REMOTE, and the_thread is undefined. + * Otherwise, location is set to OBJECTS_ERROR and + * the_thread is undefined. + * + * @note The performance of many RTEMS services depends upon + * the quick execution of the "good object" path in this + * routine. If there is a possibility of saving a few + * cycles off the execution time, this routine is worth + * further optimization attention. + */ +Thread_Control *_Thread_Get ( + Objects_Id id, + Objects_Locations *location +) +{ + uint32_t the_api; + uint32_t the_class; + Objects_Information **api_information; + Objects_Information *information; + Thread_Control *tp = (Thread_Control *) 0; + + if ( _Objects_Are_ids_equal( id, OBJECTS_ID_OF_SELF ) ) { + _Thread_Disable_dispatch(); + *location = OBJECTS_LOCAL; + tp = _Thread_Executing; + goto done; + } + + the_api = _Objects_Get_API( id ); + if ( !_Objects_Is_api_valid( the_api ) ) { + *location = OBJECTS_ERROR; + goto done; + } + + the_class = _Objects_Get_class( id ); + if ( the_class != 1 ) { /* threads are always first class :) */ + *location = OBJECTS_ERROR; + goto done; + } + + api_information = _Objects_Information_table[ the_api ]; + /* + * There is no way for this to happen if POSIX is enabled. But there + * is actually a test case in sp43 for this which trips it whether or + * not POSIX is enabled. So in the interest of safety, this is left + * on in all configurations. + */ + if ( !api_information ) { + *location = OBJECTS_ERROR; + goto done; + } + + information = api_information[ the_class ]; + if ( !information ) { + *location = OBJECTS_ERROR; + goto done; + } + + tp = (Thread_Control *) _Objects_Get( information, id, location ); + +done: + return tp; +} + diff --git a/cpukit/score/src/threadhandler.c b/cpukit/score/src/threadhandler.c new file mode 100644 index 0000000000..37185ad745 --- /dev/null +++ b/cpukit/score/src/threadhandler.c @@ -0,0 +1,189 @@ +/* + * Thread Handler + * + * + * COPYRIGHT (c) 1989-2009. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/apiext.h> +#include <rtems/score/context.h> +#include <rtems/score/interr.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/priority.h> +#include <rtems/score/states.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/userext.h> +#include <rtems/score/wkspace.h> + +#if defined(__AVR__) + #undef __USE_INIT_FINI__ +#endif + +#if defined(__USE_INIT_FINI__) + #if defined(__M32R__) + #define INIT_NAME __init + #else + #define INIT_NAME _init + #endif + + extern void INIT_NAME(void); + #define EXECUTE_GLOBAL_CONSTRUCTORS +#endif + +#if defined(__USE__MAIN__) + extern void _main(void); + #define INIT_NAME __main + #define EXECUTE_GLOBAL_CONSTRUCTORS +#endif + +/*PAGE + * + * _Thread_Handler + * + * This routine is the "primal" entry point for all threads. + * _Context_Initialize() dummies up the thread's initial context + * to cause the first Context_Switch() to jump to _Thread_Handler(). + * + * This routine is the default thread exitted error handler. It is + * returned to when a thread exits. The configured fatal error handler + * is invoked to process the exit. + * + * NOTE: + * + * On entry, it is assumed all interrupts are blocked and that this + * routine needs to set the initial isr level. This may or may not + * actually be needed by the context switch routine and as a result + * interrupts may already be at there proper level. Either way, + * setting the initial isr level properly here is safe. + * + * Input parameters: NONE + * + * Output parameters: NONE + */ + +void _Thread_Handler( void ) +{ + ISR_Level level; + Thread_Control *executing; + #if defined(EXECUTE_GLOBAL_CONSTRUCTORS) + static char doneConstructors; + char doneCons; + #endif + + executing = _Thread_Executing; + + /* + * Some CPUs need to tinker with the call frame or registers when the + * thread actually begins to execute for the first time. This is a + * hook point where the port gets a shot at doing whatever it requires. + */ + _Context_Initialization_at_thread_begin(); + + /* + * have to put level into a register for those cpu's that use + * inline asm here + */ + + level = executing->Start.isr_level; + _ISR_Set_level(level); + + #if defined(EXECUTE_GLOBAL_CONSTRUCTORS) + doneCons = doneConstructors; + doneConstructors = 1; + #endif + + #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) + #if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE ) + if ( (executing->fp_context != NULL) && + !_Thread_Is_allocated_fp( executing ) ) { + if ( _Thread_Allocated_fp != NULL ) + _Context_Save_fp( &_Thread_Allocated_fp->fp_context ); + _Thread_Allocated_fp = executing; + } + #endif + #endif + + /* + * Take care that 'begin' extensions get to complete before + * 'switch' extensions can run. This means must keep dispatch + * disabled until all 'begin' extensions complete. + */ + _User_extensions_Thread_begin( executing ); + + /* + * At this point, the dispatch disable level BETTER be 1. + */ + _Thread_Enable_dispatch(); + + #if defined(EXECUTE_GLOBAL_CONSTRUCTORS) + /* + * _init could be a weak symbol and we SHOULD test it but it isn't + * in any configuration I know of and it generates a warning on every + * RTEMS target configuration. --joel (12 May 2007) + */ + if (!doneCons) /* && (volatile void *)_init) */ { + INIT_NAME (); + } + #endif + + if ( executing->Start.prototype == THREAD_START_NUMERIC ) { + executing->Wait.return_argument = + (*(Thread_Entry_numeric) executing->Start.entry_point)( + executing->Start.numeric_argument + ); + } + #if defined(RTEMS_POSIX_API) + else if ( executing->Start.prototype == THREAD_START_POINTER ) { + executing->Wait.return_argument = + (*(Thread_Entry_pointer) executing->Start.entry_point)( + executing->Start.pointer_argument + ); + } + #endif + #if defined(FUNCTIONALITY_NOT_CURRENTLY_USED_BY_ANY_API) + else if ( executing->Start.prototype == THREAD_START_BOTH_POINTER_FIRST ) { + executing->Wait.return_argument = + (*(Thread_Entry_both_pointer_first) executing->Start.entry_point)( + executing->Start.pointer_argument, + executing->Start.numeric_argument + ); + } + else if ( executing->Start.prototype == THREAD_START_BOTH_NUMERIC_FIRST ) { + executing->Wait.return_argument = + (*(Thread_Entry_both_numeric_first) executing->Start.entry_point)( + executing->Start.numeric_argument, + executing->Start.pointer_argument + ); + } + #endif + + /* + * In the switch above, the return code from the user thread body + * was placed in return_argument. This assumed that if it returned + * anything (which is not supporting in all APIs), then it would be + * able to fit in a (void *). + */ + + _User_extensions_Thread_exitted( executing ); + + _Internal_error_Occurred( + INTERNAL_ERROR_CORE, + true, + INTERNAL_ERROR_THREAD_EXITTED + ); +} diff --git a/cpukit/score/src/threadinitialize.c b/cpukit/score/src/threadinitialize.c new file mode 100644 index 0000000000..adb0567d14 --- /dev/null +++ b/cpukit/score/src/threadinitialize.c @@ -0,0 +1,242 @@ +/* + * Thread Handler / Thread Initialize + * + * COPYRIGHT (c) 1989-2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/apiext.h> +#include <rtems/score/context.h> +#include <rtems/score/interr.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/priority.h> +#include <rtems/score/scheduler.h> +#include <rtems/score/states.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/userext.h> +#include <rtems/score/watchdog.h> +#include <rtems/score/wkspace.h> + +/*PAGE + * + * _Thread_Initialize + * + * This routine initializes the specified the thread. It allocates + * all memory associated with this thread. It completes by adding + * the thread to the local object table so operations on this + * thread id are allowed. + */ + +bool _Thread_Initialize( + Objects_Information *information, + Thread_Control *the_thread, + void *stack_area, + size_t stack_size, + bool is_fp, + Priority_Control priority, + bool is_preemptible, + Thread_CPU_budget_algorithms budget_algorithm, + Thread_CPU_budget_algorithm_callout budget_callout, + uint32_t isr_level, + Objects_Name name +) +{ + size_t actual_stack_size = 0; + void *stack = NULL; + #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) + void *fp_area; + #endif + void *sched = NULL; + void *extensions_area; + bool extension_status; + int i; + + /* + * Initialize the Ada self pointer + */ + #if __RTEMS_ADA__ + the_thread->rtems_ada_self = NULL; + #endif + + /* + * Zero out all the allocated memory fields + */ + for ( i=0 ; i <= THREAD_API_LAST ; i++ ) + the_thread->API_Extensions[i] = NULL; + + extensions_area = NULL; + the_thread->libc_reent = NULL; + + #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) + fp_area = NULL; + #endif + + /* + * Allocate and Initialize the stack for this thread. + */ + #if !defined(RTEMS_SCORE_THREAD_ENABLE_USER_PROVIDED_STACK_VIA_API) + actual_stack_size = _Thread_Stack_Allocate( the_thread, stack_size ); + if ( !actual_stack_size || actual_stack_size < stack_size ) + return false; /* stack allocation failed */ + + stack = the_thread->Start.stack; + #else + if ( !stack_area ) { + actual_stack_size = _Thread_Stack_Allocate( the_thread, stack_size ); + if ( !actual_stack_size || actual_stack_size < stack_size ) + return false; /* stack allocation failed */ + + stack = the_thread->Start.stack; + the_thread->Start.core_allocated_stack = true; + } else { + stack = stack_area; + actual_stack_size = stack_size; + the_thread->Start.core_allocated_stack = false; + } + #endif + + _Stack_Initialize( + &the_thread->Start.Initial_stack, + stack, + actual_stack_size + ); + + /* + * Allocate the floating point area for this thread + */ + #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) + if ( is_fp ) { + fp_area = _Workspace_Allocate( CONTEXT_FP_SIZE ); + if ( !fp_area ) + goto failed; + fp_area = _Context_Fp_start( fp_area, 0 ); + } + the_thread->fp_context = fp_area; + the_thread->Start.fp_context = fp_area; + #endif + + /* + * Initialize the thread timer + */ + _Watchdog_Initialize( &the_thread->Timer, NULL, 0, NULL ); + + #ifdef __RTEMS_STRICT_ORDER_MUTEX__ + /* Initialize the head of chain of held mutexes */ + _Chain_Initialize_empty(&the_thread->lock_mutex); + #endif + + /* + * Allocate the extensions area for this thread + */ + if ( _Thread_Maximum_extensions ) { + extensions_area = _Workspace_Allocate( + (_Thread_Maximum_extensions + 1) * sizeof( void * ) + ); + if ( !extensions_area ) + goto failed; + } + the_thread->extensions = (void **) extensions_area; + + /* + * Clear the extensions area so extension users can determine + * if they are linked to the thread. An extension user may + * create the extension long after tasks have been created + * so they cannot rely on the thread create user extension + * call. + */ + if ( the_thread->extensions ) { + for ( i = 0; i <= _Thread_Maximum_extensions ; i++ ) + the_thread->extensions[i] = NULL; + } + + /* + * General initialization + */ + + the_thread->Start.is_preemptible = is_preemptible; + the_thread->Start.budget_algorithm = budget_algorithm; + the_thread->Start.budget_callout = budget_callout; + + switch ( budget_algorithm ) { + case THREAD_CPU_BUDGET_ALGORITHM_NONE: + case THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE: + break; + #if defined(RTEMS_SCORE_THREAD_ENABLE_EXHAUST_TIMESLICE) + case THREAD_CPU_BUDGET_ALGORITHM_EXHAUST_TIMESLICE: + the_thread->cpu_time_budget = _Thread_Ticks_per_timeslice; + break; + #endif + #if defined(RTEMS_SCORE_THREAD_ENABLE_SCHEDULER_CALLOUT) + case THREAD_CPU_BUDGET_ALGORITHM_CALLOUT: + break; + #endif + } + + the_thread->Start.isr_level = isr_level; + + the_thread->current_state = STATES_DORMANT; + the_thread->Wait.queue = NULL; + the_thread->resource_count = 0; + the_thread->real_priority = priority; + the_thread->Start.initial_priority = priority; + sched =_Scheduler_Allocate( the_thread ); + if ( !sched ) + goto failed; + _Thread_Set_priority( the_thread, priority ); + + /* + * Initialize the CPU usage statistics + */ + #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__ + _Timestamp_Set_to_zero( &the_thread->cpu_time_used ); + #else + the_thread->cpu_time_used = 0; + #endif + + /* + * Open the object + */ + _Objects_Open( information, &the_thread->Object, name ); + + /* + * We assume the Allocator Mutex is locked and dispatching is + * enabled when we get here. We want to be able to run the + * user extensions with dispatching enabled. The Allocator + * Mutex provides sufficient protection to let the user extensions + * run safely. + */ + extension_status = _User_extensions_Thread_create( the_thread ); + if ( extension_status ) + return true; + +failed: + _Workspace_Free( the_thread->libc_reent ); + + for ( i=0 ; i <= THREAD_API_LAST ; i++ ) + _Workspace_Free( the_thread->API_Extensions[i] ); + + _Workspace_Free( extensions_area ); + + #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) + _Workspace_Free( fp_area ); + #endif + + _Workspace_Free( sched ); + + _Thread_Stack_Free( the_thread ); + return false; +} diff --git a/cpukit/score/src/threadloadenv.c b/cpukit/score/src/threadloadenv.c new file mode 100644 index 0000000000..a2d5318c78 --- /dev/null +++ b/cpukit/score/src/threadloadenv.c @@ -0,0 +1,74 @@ +/* + * Thread Handler + * + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/apiext.h> +#include <rtems/score/context.h> +#include <rtems/score/interr.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/priority.h> +#include <rtems/score/states.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/userext.h> +#include <rtems/score/wkspace.h> + +/*PAGE + * + * _Thread_Load_environment + * + * Load starting environment for another thread from its start area in the + * thread. Only called from t_restart and t_start. + * + * Input parameters: + * the_thread - thread control block pointer + * + * Output parameters: NONE + */ + +void _Thread_Load_environment( + Thread_Control *the_thread +) +{ + bool is_fp; + +#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) + if ( the_thread->Start.fp_context ) { + the_thread->fp_context = the_thread->Start.fp_context; + _Context_Initialize_fp( &the_thread->fp_context ); + is_fp = true; + } else +#endif + is_fp = false; + + the_thread->is_preemptible = the_thread->Start.is_preemptible; + the_thread->budget_algorithm = the_thread->Start.budget_algorithm; + the_thread->budget_callout = the_thread->Start.budget_callout; + + _Context_Initialize( + &the_thread->Registers, + the_thread->Start.Initial_stack.area, + the_thread->Start.Initial_stack.size, + the_thread->Start.isr_level, + _Thread_Handler, + is_fp + ); + +} diff --git a/cpukit/score/src/threadmp.c b/cpukit/score/src/threadmp.c new file mode 100644 index 0000000000..ffd611b4ac --- /dev/null +++ b/cpukit/score/src/threadmp.c @@ -0,0 +1,168 @@ +/* + * Multiprocessing Support for the Thread Handler + * + * + * COPYRIGHT (c) 1989-2006. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/priority.h> +#include <rtems/score/thread.h> +#include <rtems/score/mpci.h> +#include <rtems/score/wkspace.h> +#include <rtems/score/isr.h> + +/*PAGE + * + * _Thread_MP_Handler_initialization + * + */ + +void _Thread_MP_Handler_initialization ( + uint32_t maximum_proxies +) +{ + + _Chain_Initialize_empty( &_Thread_MP_Active_proxies ); + + if ( maximum_proxies == 0 ) { + _Chain_Initialize_empty( &_Thread_MP_Inactive_proxies ); + return; + } + + + _Chain_Initialize( + &_Thread_MP_Inactive_proxies, + _Workspace_Allocate_or_fatal_error( + maximum_proxies * sizeof( Thread_Proxy_control ) + ), + maximum_proxies, + sizeof( Thread_Proxy_control ) + ); + +} + +/*PAGE + * + * _Thread_MP_Allocate_proxy + * + */ + +Thread_Control *_Thread_MP_Allocate_proxy ( + States_Control the_state +) +{ + Thread_Control *the_thread; + Thread_Proxy_control *the_proxy; + + the_thread = (Thread_Control *)_Chain_Get( &_Thread_MP_Inactive_proxies ); + + if ( !_Thread_Is_null( the_thread ) ) { + + the_proxy = (Thread_Proxy_control *) the_thread; + + _Thread_Executing->Wait.return_code = THREAD_STATUS_PROXY_BLOCKING; + + the_proxy->receive_packet = _MPCI_Receive_server_tcb->receive_packet; + + the_proxy->Object.id = _MPCI_Receive_server_tcb->receive_packet->source_tid; + + the_proxy->current_priority = + _MPCI_Receive_server_tcb->receive_packet->source_priority; + + the_proxy->current_state = _States_Set( STATES_DORMANT, the_state ); + + the_proxy->Wait = _Thread_Executing->Wait; + + _Chain_Append( &_Thread_MP_Active_proxies, &the_proxy->Active ); + + return the_thread; + } + + _Internal_error_Occurred( + INTERNAL_ERROR_CORE, + true, + INTERNAL_ERROR_OUT_OF_PROXIES + ); + + /* + * NOTE: The following return ensures that the compiler will + * think that all paths return a value. + */ + + return NULL; +} + +/*PAGE + * + * _Thread_MP_Find_proxy + * + */ + +/* + * The following macro provides the offset of the Active element + * in the Thread_Proxy_control structure. This is the logical + * equivalent of the POSITION attribute in Ada. + */ + +#define _Thread_MP_Proxy_Active_offset \ + ((uint32_t)&(((Thread_Proxy_control *)0))->Active) + +Thread_Control *_Thread_MP_Find_proxy ( + Objects_Id the_id +) +{ + + Chain_Node *proxy_node; + Thread_Control *the_thread; + ISR_Level level; + +restart: + + _ISR_Disable( level ); + + for ( proxy_node = _Chain_First( &_Thread_MP_Active_proxies ); + !_Chain_Is_tail( &_Thread_MP_Active_proxies, proxy_node ) ; + ) { + + the_thread = (Thread_Control *) _Addresses_Subtract_offset( + proxy_node, + _Thread_MP_Proxy_Active_offset + ); + + if ( _Objects_Are_ids_equal( the_thread->Object.id, the_id ) ) { + _ISR_Enable( level ); + return the_thread; + } + + _ISR_Flash( level ); + + proxy_node = _Chain_Next( proxy_node ); + + /* + * A proxy which is only dormant is not in a blocking state. + * Therefore, we are looking at proxy which has been moved from + * active to inactive chain (by an ISR) and need to restart + * the search. + */ + + if ( _States_Is_only_dormant( the_thread->current_state ) ) { + _ISR_Enable( level ); + goto restart; + } + } + + _ISR_Enable( level ); + return NULL; +} diff --git a/cpukit/score/src/threadq.c b/cpukit/score/src/threadq.c new file mode 100644 index 0000000000..baa85a13e1 --- /dev/null +++ b/cpukit/score/src/threadq.c @@ -0,0 +1,66 @@ +/* + * Thread Queue Handler + * + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/tqdata.h> + +/*PAGE + * + * _Thread_queue_Initialize + * + * This routine initializes the specified threadq. + * + * Input parameters: + * the_thread_queue - pointer to a threadq header + * discipline - queueing discipline + * state - state of waiting threads + * timeout_status - return on a timeout + * + * Output parameters: NONE + */ + +void _Thread_queue_Initialize( + Thread_queue_Control *the_thread_queue, + Thread_queue_Disciplines the_discipline, + States_Control state, + uint32_t timeout_status +) +{ + the_thread_queue->state = state; + the_thread_queue->discipline = the_discipline; + the_thread_queue->timeout_status = timeout_status; + the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_SYNCHRONIZED; + + if ( the_discipline == THREAD_QUEUE_DISCIPLINE_PRIORITY ) { + uint32_t index; + + for( index=0 ; + index < TASK_QUEUE_DATA_NUMBER_OF_PRIORITY_HEADERS ; + index++) + _Chain_Initialize_empty( &the_thread_queue->Queues.Priority[index] ); + } else { /* must be THREAD_QUEUE_DISCIPLINE_FIFO */ + _Chain_Initialize_empty( &the_thread_queue->Queues.Fifo ); + } + +} diff --git a/cpukit/score/src/threadqdequeue.c b/cpukit/score/src/threadqdequeue.c new file mode 100644 index 0000000000..b9213968b8 --- /dev/null +++ b/cpukit/score/src/threadqdequeue.c @@ -0,0 +1,72 @@ +/* + * Thread Queue Handler + * + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/tqdata.h> + +/*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 *(*dequeue_p)( Thread_queue_Control * ); + Thread_Control *the_thread; + ISR_Level level; + Thread_blocking_operation_States sync_state; + + if ( the_thread_queue->discipline == THREAD_QUEUE_DISCIPLINE_PRIORITY ) + dequeue_p = _Thread_queue_Dequeue_priority; + else /* must be THREAD_QUEUE_DISCIPLINE_FIFO */ + dequeue_p = _Thread_queue_Dequeue_fifo; + + the_thread = (*dequeue_p)( the_thread_queue ); + _ISR_Disable( level ); + if ( !the_thread ) { + sync_state = the_thread_queue->sync_state; + if ( (sync_state == THREAD_BLOCKING_OPERATION_TIMEOUT) || + (sync_state == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED) ) { + the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_SATISFIED; + the_thread = _Thread_Executing; + } + } + _ISR_Enable( level ); + return the_thread; +} diff --git a/cpukit/score/src/threadqdequeuefifo.c b/cpukit/score/src/threadqdequeuefifo.c new file mode 100644 index 0000000000..0ea36791fc --- /dev/null +++ b/cpukit/score/src/threadqdequeuefifo.c @@ -0,0 +1,79 @@ +/* + * Thread Queue Handler + * + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/tqdata.h> + +/*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 ); + + the_thread->Wait.queue = NULL; + 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; + } + + _ISR_Enable( level ); + return NULL; +} diff --git a/cpukit/score/src/threadqdequeuepriority.c b/cpukit/score/src/threadqdequeuepriority.c new file mode 100644 index 0000000000..1a7bc7037a --- /dev/null +++ b/cpukit/score/src/threadqdequeuepriority.c @@ -0,0 +1,125 @@ +/* + * Thread Queue Handler + * + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/tqdata.h> + +/*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 +) +{ + uint32_t index; + ISR_Level level; + Thread_Control *the_thread = NULL; /* just to remove warnings */ + Thread_Control *new_first_thread; + Chain_Node *head; + Chain_Node *tail; + 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 *) _Chain_First( + &the_thread_queue->Queues.Priority[ index ] + ); + goto dequeue; + } + } + + /* + * We did not find a thread to unblock. + */ + _ISR_Enable( level ); + return NULL; + +dequeue: + the_thread->Wait.queue = NULL; + new_first_node = _Chain_First( &the_thread->Wait.Block2n ); + 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 = _Chain_Last( &the_thread->Wait.Block2n ); + 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 */ + head = _Chain_Head( &new_first_thread->Wait.Block2n ); + tail = _Chain_Tail( &new_first_thread->Wait.Block2n ); + + new_second_node->previous = head; + head->next = new_second_node; + tail->previous = last_node; + last_node->next = tail; + } + } 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 ); +} diff --git a/cpukit/score/src/threadqenqueue.c b/cpukit/score/src/threadqenqueue.c new file mode 100644 index 0000000000..dbb1661feb --- /dev/null +++ b/cpukit/score/src/threadqenqueue.c @@ -0,0 +1,97 @@ +/* + * Thread Queue Handler + * + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/tqdata.h> + +/*PAGE + * + * _Thread_queue_Enqueue_with_handler + * + * 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_with_handler( + Thread_queue_Control *the_thread_queue, + Watchdog_Interval timeout, + Thread_queue_Timeout_callout handler +) +{ + Thread_Control *the_thread; + ISR_Level level; + Thread_blocking_operation_States sync_state; + Thread_blocking_operation_States (*enqueue_p)( + Thread_queue_Control *, + Thread_Control *, + ISR_Level * + ); + + 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 + /* + * Set the blocking state for this thread queue in the thread. + */ + _Thread_Set_state( the_thread, the_thread_queue->state ); + + /* + * If the thread wants to timeout, then schedule its timer. + */ + if ( timeout ) { + _Watchdog_Initialize( + &the_thread->Timer, + handler, + the_thread->Object.id, + NULL + ); + + _Watchdog_Insert_ticks( &the_thread->Timer, timeout ); + } + + /* + * Now enqueue the thread per the discipline for this thread queue. + */ + if ( the_thread_queue->discipline == THREAD_QUEUE_DISCIPLINE_PRIORITY ) + enqueue_p = _Thread_queue_Enqueue_priority; + else /* must be THREAD_QUEUE_DISCIPLINE_FIFO */ + enqueue_p = _Thread_queue_Enqueue_fifo; + + sync_state = (*enqueue_p)( the_thread_queue, the_thread, &level ); + if ( sync_state != THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED ) + _Thread_blocking_operation_Cancel( sync_state, the_thread, level ); +} diff --git a/cpukit/score/src/threadqenqueuefifo.c b/cpukit/score/src/threadqenqueuefifo.c new file mode 100644 index 0000000000..da3c809212 --- /dev/null +++ b/cpukit/score/src/threadqenqueuefifo.c @@ -0,0 +1,78 @@ +/* + * Thread Queue Handler + * + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/tqdata.h> + +/*PAGE + * + * _Thread_queue_Enqueue_fifo + * + * This routine places a blocked thread on a FIFO thread queue. + * + * Input parameters: + * the_thread_queue - pointer to threadq + * the_thread - pointer to the thread to block + * + * Output parameters: NONE + * + * INTERRUPT LATENCY: + * only case + */ + +Thread_blocking_operation_States _Thread_queue_Enqueue_fifo ( + Thread_queue_Control *the_thread_queue, + Thread_Control *the_thread, + ISR_Level *level_p +) +{ + Thread_blocking_operation_States sync_state; + ISR_Level level; + + _ISR_Disable( level ); + + sync_state = the_thread_queue->sync_state; + the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_SYNCHRONIZED; + if (sync_state == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED) { + _Chain_Append_unprotected( + &the_thread_queue->Queues.Fifo, + &the_thread->Object.Node + ); + the_thread->Wait.queue = the_thread_queue; + + the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_SYNCHRONIZED; + _ISR_Enable( level ); + return THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED; + } + + /* + * An interrupt completed the thread's blocking request. + * For example, the blocking thread could have been given + * the mutex by an ISR or timed out. + * + * WARNING! Returning with interrupts disabled! + */ + *level_p = level; + return sync_state; +} diff --git a/cpukit/score/src/threadqenqueuepriority.c b/cpukit/score/src/threadqenqueuepriority.c new file mode 100644 index 0000000000..0d30529e0f --- /dev/null +++ b/cpukit/score/src/threadqenqueuepriority.c @@ -0,0 +1,197 @@ +/* + * Thread Queue Handler - Enqueue By Priority + * + * COPYRIGHT (c) 1989-2009. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/tqdata.h> + +/* + * Support the user forcing the unrolling to be disabled. + */ +#if __RTEMS_DO_NOT_UNROLL_THREADQ_ENQUEUE_PRIORITY__ + #undef CPU_UNROLL_ENQUEUE_PRIORITY + #define CPU_UNROLL_ENQUEUE_PRIORITY FALSE +#endif + +/*PAGE + * + * _Thread_queue_Enqueue_priority + * + * This routine places a blocked thread on a priority thread queue. + * + * Input parameters: + * the_thread_queue - pointer to threadq + * thread - thread to insert + * + * Output parameters: NONE + * + * INTERRUPT LATENCY: + * forward less than + * forward equal + */ + +Thread_blocking_operation_States _Thread_queue_Enqueue_priority ( + Thread_queue_Control *the_thread_queue, + Thread_Control *the_thread, + ISR_Level *level_p +) +{ + Priority_Control search_priority; + Thread_Control *search_thread; + ISR_Level level; + Chain_Control *header; + uint32_t 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; + + _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 *) _Chain_First( header ); + 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_BLOCKING_OPERATION_NOTHING_HAPPENED ) + goto synchronize; + + the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_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; + the_thread->Wait.queue = the_thread_queue; + _ISR_Enable( level ); + return THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED; + +restart_reverse_search: + search_priority = PRIORITY_MAXIMUM + 1; + + _ISR_Disable( level ); + search_thread = (Thread_Control *) _Chain_Last( header ); + 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_BLOCKING_OPERATION_NOTHING_HAPPENED ) + goto synchronize; + + the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_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; + the_thread->Wait.queue = the_thread_queue; + _ISR_Enable( level ); + return THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED; + +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; + the_thread->Wait.queue = the_thread_queue; + _ISR_Enable( level ); + return THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED; + +synchronize: + /* + * An interrupt completed the thread's blocking request. + * For example, the blocking thread could have been given + * the mutex by an ISR or timed out. + * + * WARNING! Returning with interrupts disabled! + */ + *level_p = level; + return the_thread_queue->sync_state; +} diff --git a/cpukit/score/src/threadqextract.c b/cpukit/score/src/threadqextract.c new file mode 100644 index 0000000000..21aa2c2a46 --- /dev/null +++ b/cpukit/score/src/threadqextract.c @@ -0,0 +1,58 @@ +/* + * Thread Queue Handler + * + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/tqdata.h> + +/*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 +) +{ + /* + * Can not use indirect function pointer here since Extract priority + * is a macro and the underlying methods do not have the same signature. + */ + if ( the_thread_queue->discipline == THREAD_QUEUE_DISCIPLINE_PRIORITY ) + _Thread_queue_Extract_priority( the_thread_queue, the_thread ); + else /* must be THREAD_QUEUE_DISCIPLINE_FIFO */ + _Thread_queue_Extract_fifo( the_thread_queue, the_thread ); + +} diff --git a/cpukit/score/src/threadqextractfifo.c b/cpukit/score/src/threadqextractfifo.c new file mode 100644 index 0000000000..f40464d73c --- /dev/null +++ b/cpukit/score/src/threadqextractfifo.c @@ -0,0 +1,78 @@ +/* + * Thread Queue Handler + * + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/tqdata.h> + +/*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 __attribute__((unused)), + 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 ); + + the_thread->Wait.queue = NULL; + + 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 + +} diff --git a/cpukit/score/src/threadqextractpriority.c b/cpukit/score/src/threadqextractpriority.c new file mode 100644 index 0000000000..d4ddc2aa84 --- /dev/null +++ b/cpukit/score/src/threadqextractpriority.c @@ -0,0 +1,125 @@ +/* + * Thread Queue Handler + * + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/tqdata.h> + +/*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 + * requeuing - true if requeuing and should not alter timeout or state + * + * Output parameters: NONE + * + * INTERRUPT LATENCY: + * EXTRACT_PRIORITY + */ + +void _Thread_queue_Extract_priority_helper( + Thread_queue_Control *the_thread_queue __attribute__((unused)), + Thread_Control *the_thread, + bool requeuing +) +{ + ISR_Level level; + Chain_Node *head; + Chain_Node *tail; + 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 ) ) { + _ISR_Enable( level ); + return; + } + + /* + * The thread was actually waiting on a thread queue so let's remove it. + */ + + next_node = the_node->next; + previous_node = the_node->previous; + + if ( !_Chain_Is_empty( &the_thread->Wait.Block2n ) ) { + new_first_node = _Chain_First( &the_thread->Wait.Block2n ); + new_first_thread = (Thread_Control *) new_first_node; + last_node = _Chain_Last( &the_thread->Wait.Block2n ); + 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 */ + head = _Chain_Head( &new_first_thread->Wait.Block2n ); + tail = _Chain_Tail( &new_first_thread->Wait.Block2n ); + + new_second_node->previous = head; + head->next = new_second_node; + tail->previous = last_node; + last_node->next = tail; + } + } else { + previous_node->next = next_node; + next_node->previous = previous_node; + } + + /* + * If we are not supposed to touch timers or the thread's state, return. + */ + + if ( requeuing ) { + _ISR_Enable( level ); + return; + } + + 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 +} diff --git a/cpukit/score/src/threadqextractwithproxy.c b/cpukit/score/src/threadqextractwithproxy.c new file mode 100644 index 0000000000..450702b0e4 --- /dev/null +++ b/cpukit/score/src/threadqextractwithproxy.c @@ -0,0 +1,67 @@ +/* + * Thread Queue Handler + * + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/tqdata.h> + +/*PAGE + * + * _Thread_queue_Extract_with_proxy + * + * This routine extracts the_thread from the_thread_queue + * and ensures that if there is a proxy for this task on + * another node, it is also dealt with. + * + * XXX + */ + +bool _Thread_queue_Extract_with_proxy( + Thread_Control *the_thread +) +{ + States_Control state; + + state = the_thread->current_state; + + if ( _States_Is_waiting_on_thread_queue( state ) ) { + #if defined(RTEMS_MULTIPROCESSING) + if ( _States_Is_waiting_for_rpc_reply( state ) && + _States_Is_locally_blocked( state ) ) { + Objects_Information *the_information; + Objects_Thread_queue_Extract_callout proxy_extract_callout; + + the_information = _Objects_Get_information_id( the_thread->Wait.id ); + proxy_extract_callout = + (Objects_Thread_queue_Extract_callout) the_information->extract; + + if ( proxy_extract_callout ) + (*proxy_extract_callout)( the_thread ); + } + #endif + _Thread_queue_Extract( the_thread->Wait.queue, the_thread ); + + return true; + } + return false; +} diff --git a/cpukit/score/src/threadqfirst.c b/cpukit/score/src/threadqfirst.c new file mode 100644 index 0000000000..8e268b87d9 --- /dev/null +++ b/cpukit/score/src/threadqfirst.c @@ -0,0 +1,54 @@ +/* + * Thread Queue Handler + * + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/tqdata.h> + +/*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 * (*first_p)(Thread_queue_Control *); + + if ( the_thread_queue->discipline == THREAD_QUEUE_DISCIPLINE_PRIORITY ) + first_p = _Thread_queue_First_priority; + else /* must be THREAD_QUEUE_DISCIPLINE_FIFO */ + first_p = _Thread_queue_First_fifo; + + return (*first_p)( the_thread_queue ); +} diff --git a/cpukit/score/src/threadqfirstfifo.c b/cpukit/score/src/threadqfirstfifo.c new file mode 100644 index 0000000000..bde7b45054 --- /dev/null +++ b/cpukit/score/src/threadqfirstfifo.c @@ -0,0 +1,50 @@ +/* + * Thread Queue Handler + * + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/tqdata.h> + +/*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 *) _Chain_First( &the_thread_queue->Queues.Fifo ); + + return NULL; +} diff --git a/cpukit/score/src/threadqfirstpriority.c b/cpukit/score/src/threadqfirstpriority.c new file mode 100644 index 0000000000..e5f4bccfe4 --- /dev/null +++ b/cpukit/score/src/threadqfirstpriority.c @@ -0,0 +1,57 @@ +/* + * Thread Queue Handler + * + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/tqdata.h> + +/*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 +) +{ + uint32_t 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 *) _Chain_First( + &the_thread_queue->Queues.Priority[ index ] + ); + } + return NULL; +} diff --git a/cpukit/score/src/threadqflush.c b/cpukit/score/src/threadqflush.c new file mode 100644 index 0000000000..b777aa3fa1 --- /dev/null +++ b/cpukit/score/src/threadqflush.c @@ -0,0 +1,62 @@ +/* + * Thread Queue Handler + * + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/tqdata.h> + +/*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, +#if defined(RTEMS_MULTIPROCESSING) + Thread_queue_Flush_callout remote_extract_callout, +#else + Thread_queue_Flush_callout remote_extract_callout __attribute__((unused)), +#endif + uint32_t 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; + } +} diff --git a/cpukit/score/src/threadqprocesstimeout.c b/cpukit/score/src/threadqprocesstimeout.c new file mode 100644 index 0000000000..9683a6e728 --- /dev/null +++ b/cpukit/score/src/threadqprocesstimeout.c @@ -0,0 +1,57 @@ +/* + * Thread Queue Handler - Process Timeout Handler + * + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/tqdata.h> + +void _Thread_queue_Process_timeout( + Thread_Control *the_thread +) +{ + Thread_queue_Control *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_BLOCKING_OPERATION_SYNCHRONIZED && + _Thread_Is_executing( the_thread ) ) { + if ( the_thread_queue->sync_state != THREAD_BLOCKING_OPERATION_SATISFIED ) { + the_thread->Wait.return_code = the_thread->Wait.queue->timeout_status; + the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_TIMEOUT; + } + } else { + the_thread->Wait.return_code = the_thread->Wait.queue->timeout_status; + _Thread_queue_Extract( the_thread->Wait.queue, the_thread ); + } +} + diff --git a/cpukit/score/src/threadqrequeue.c b/cpukit/score/src/threadqrequeue.c new file mode 100644 index 0000000000..bba22148fb --- /dev/null +++ b/cpukit/score/src/threadqrequeue.c @@ -0,0 +1,74 @@ +/* + * Thread Queue Handler + * + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/tqdata.h> + +/*PAGE + * + * _Thread_queue_Requeue + * + * This routine is invoked when a thread changes priority and should be + * moved to a different position on the thread queue. + * + * 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_Requeue( + Thread_queue_Control *the_thread_queue, + Thread_Control *the_thread +) +{ + /* + * Just in case the thread really wasn't blocked on a thread queue + * when we get here. + */ + if ( !the_thread_queue ) + return; + + /* + * If queueing by FIFO, there is nothing to do. This only applies to + * priority blocking discipline. + */ + if ( the_thread_queue->discipline == THREAD_QUEUE_DISCIPLINE_PRIORITY ) { + Thread_queue_Control *tq = the_thread_queue; + ISR_Level level; + ISR_Level level_ignored; + + _ISR_Disable( level ); + if ( _States_Is_waiting_on_thread_queue( the_thread->current_state ) ) { + _Thread_queue_Enter_critical_section( tq ); + _Thread_queue_Extract_priority_helper( tq, the_thread, true ); + (void) _Thread_queue_Enqueue_priority( tq, the_thread, &level_ignored ); + } + _ISR_Enable( level ); + } +} + diff --git a/cpukit/score/src/threadqtimeout.c b/cpukit/score/src/threadqtimeout.c new file mode 100644 index 0000000000..4fa1d5817b --- /dev/null +++ b/cpukit/score/src/threadqtimeout.c @@ -0,0 +1,60 @@ +/* + * Thread Queue Handler + * + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/tqdata.h> + +/* + * _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 __attribute__((unused)) +) +{ + Thread_Control *the_thread; + Objects_Locations location; + + the_thread = _Thread_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: +#if defined(RTEMS_MULTIPROCESSING) + case OBJECTS_REMOTE: /* impossible */ +#endif + break; + case OBJECTS_LOCAL: + _Thread_queue_Process_timeout( the_thread ); + _Thread_Unnest_dispatch(); + break; + } +} diff --git a/cpukit/score/src/threadready.c b/cpukit/score/src/threadready.c new file mode 100644 index 0000000000..9e3a285d22 --- /dev/null +++ b/cpukit/score/src/threadready.c @@ -0,0 +1,51 @@ +/* + * Thread Handler / Thread Ready + * + * COPYRIGHT (c) 1989-2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/apiext.h> +#include <rtems/score/context.h> +#include <rtems/score/interr.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/priority.h> +#include <rtems/score/scheduler.h> +#include <rtems/score/states.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/userext.h> +#include <rtems/score/wkspace.h> + +/* + * INTERRUPT LATENCY: + * ready chain + * select heir + */ +void _Thread_Ready( + Thread_Control *the_thread +) +{ + ISR_Level level; + + _ISR_Disable( level ); + + the_thread->current_state = STATES_READY; + + _Scheduler_Unblock( the_thread ); + + _ISR_Enable( level ); +} diff --git a/cpukit/score/src/threadreset.c b/cpukit/score/src/threadreset.c new file mode 100644 index 0000000000..57b5605d30 --- /dev/null +++ b/cpukit/score/src/threadreset.c @@ -0,0 +1,67 @@ +/* + * Thread Handler + * + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/apiext.h> +#include <rtems/score/context.h> +#include <rtems/score/interr.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/priority.h> +#include <rtems/score/states.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/userext.h> +#include <rtems/score/wkspace.h> + +/* + * _Thread_Reset + * + * DESCRIPTION: + * + * This routine resets a thread to its initial stat but does + * not actually restart it. Some APIs do this in separate + * operations and this division helps support this. + */ + +void _Thread_Reset( + Thread_Control *the_thread, + void *pointer_argument, + Thread_Entry_numeric_type numeric_argument +) +{ + the_thread->resource_count = 0; + the_thread->is_preemptible = the_thread->Start.is_preemptible; + the_thread->budget_algorithm = the_thread->Start.budget_algorithm; + the_thread->budget_callout = the_thread->Start.budget_callout; + + the_thread->Start.pointer_argument = pointer_argument; + the_thread->Start.numeric_argument = numeric_argument; + + if ( !_Thread_queue_Extract_with_proxy( the_thread ) ) { + + if ( _Watchdog_Is_active( &the_thread->Timer ) ) + (void) _Watchdog_Remove( &the_thread->Timer ); + } + + if ( the_thread->current_priority != the_thread->Start.initial_priority ) { + the_thread->real_priority = the_thread->Start.initial_priority; + _Thread_Set_priority( the_thread, the_thread->Start.initial_priority ); + } +} diff --git a/cpukit/score/src/threadrestart.c b/cpukit/score/src/threadrestart.c new file mode 100644 index 0000000000..37af4d805f --- /dev/null +++ b/cpukit/score/src/threadrestart.c @@ -0,0 +1,68 @@ +/* + * Thread Handler + * + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/apiext.h> +#include <rtems/score/context.h> +#include <rtems/score/interr.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/priority.h> +#include <rtems/score/states.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/userext.h> +#include <rtems/score/wkspace.h> + +/* + * _Thread_Restart + * + * DESCRIPTION: + * + * This support routine restarts the specified task in a way that the + * next time this thread executes, it will begin execution at its + * original starting point. + */ + +bool _Thread_Restart( + Thread_Control *the_thread, + void *pointer_argument, + Thread_Entry_numeric_type numeric_argument +) +{ + if ( !_States_Is_dormant( the_thread->current_state ) ) { + + _Thread_Set_transient( the_thread ); + + _Thread_Reset( the_thread, pointer_argument, numeric_argument ); + + _Thread_Load_environment( the_thread ); + + _Thread_Ready( the_thread ); + + _User_extensions_Thread_restart( the_thread ); + + if ( _Thread_Is_executing ( the_thread ) ) + _Thread_Restart_self(); + + return true; + } + + return false; +} diff --git a/cpukit/score/src/threadsetpriority.c b/cpukit/score/src/threadsetpriority.c new file mode 100644 index 0000000000..678df56fc8 --- /dev/null +++ b/cpukit/score/src/threadsetpriority.c @@ -0,0 +1,30 @@ +/* + * Thread Handler / Thread Set Priority + * + * COPYRIGHT (c) 1989-2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/scheduler.h> +#include <rtems/score/thread.h> + +void _Thread_Set_priority( + Thread_Control *the_thread, + Priority_Control new_priority +) +{ + the_thread->current_priority = new_priority; + + _Scheduler_Update( the_thread ); +} diff --git a/cpukit/score/src/threadsetstate.c b/cpukit/score/src/threadsetstate.c new file mode 100644 index 0000000000..1dcf33344c --- /dev/null +++ b/cpukit/score/src/threadsetstate.c @@ -0,0 +1,58 @@ +/* + * Thread Handler / Thread Set State + * + * COPYRIGHT (c) 1989-2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/apiext.h> +#include <rtems/score/context.h> +#include <rtems/score/interr.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/priority.h> +#include <rtems/score/scheduler.h> +#include <rtems/score/states.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/userext.h> +#include <rtems/score/wkspace.h> + +/* + * INTERRUPT LATENCY: + * ready chain + * select map + */ +void _Thread_Set_state( + Thread_Control *the_thread, + States_Control state +) +{ + ISR_Level level; + + _ISR_Disable( level ); + if ( !_States_Is_ready( the_thread->current_state ) ) { + the_thread->current_state = + _States_Set( state, the_thread->current_state ); + _ISR_Enable( level ); + return; + } + + the_thread->current_state = state; + + _Scheduler_Block( the_thread ); + + _ISR_Enable( level ); +} diff --git a/cpukit/score/src/threadsettransient.c b/cpukit/score/src/threadsettransient.c new file mode 100644 index 0000000000..11f91ed30e --- /dev/null +++ b/cpukit/score/src/threadsettransient.c @@ -0,0 +1,56 @@ +/* + * Thread Handler / Thread Set Transient + * + * COPYRIGHT (c) 1989-2011. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/apiext.h> +#include <rtems/score/context.h> +#include <rtems/score/interr.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/priority.h> +#include <rtems/score/scheduler.h> +#include <rtems/score/schedulerpriority.h> +#include <rtems/score/states.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/userext.h> +#include <rtems/score/wkspace.h> + +/* + * INTERRUPT LATENCY: + * only case + */ +void _Thread_Set_transient( + Thread_Control *the_thread +) +{ + ISR_Level level; + uint32_t old_state; + + _ISR_Disable( level ); + + old_state = the_thread->current_state; + the_thread->current_state = _States_Set( STATES_TRANSIENT, old_state ); + + if ( _States_Is_ready( old_state ) ) { + _Scheduler_Extract( the_thread ); + } + + _ISR_Enable( level ); + +} diff --git a/cpukit/score/src/threadstackallocate.c b/cpukit/score/src/threadstackallocate.c new file mode 100644 index 0000000000..d8e21ea1f6 --- /dev/null +++ b/cpukit/score/src/threadstackallocate.c @@ -0,0 +1,84 @@ +/* + * Thread Handler - Stack Allocate Helper + * + * COPYRIGHT (c) 1989-2010. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/apiext.h> +#include <rtems/score/context.h> +#include <rtems/score/interr.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/priority.h> +#include <rtems/score/states.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/userext.h> +#include <rtems/score/wkspace.h> +#include <rtems/config.h> + +/*PAGE + * + * _Thread_Stack_Allocate + * + * Allocate the requested stack space for the thread. + * return the actual size allocated after any adjustment + * or return zero if the allocation failed. + * Set the Start.stack field to the address of the stack + */ + +size_t _Thread_Stack_Allocate( + Thread_Control *the_thread, + size_t stack_size +) +{ + void *stack_addr = 0; + size_t the_stack_size; + + the_stack_size = _Stack_Ensure_minimum( stack_size ); + + /* + * Call ONLY the CPU table stack allocate hook, _or_ the + * the RTEMS workspace allocate. This is so the stack free + * routine can call the correct deallocation routine. + */ + + if ( Configuration.stack_allocate_hook ) { + stack_addr = (*Configuration.stack_allocate_hook)( the_stack_size ); + } else { + + /* + * First pad the requested size so we allocate enough memory + * so the context initialization can align it properly. The address + * returned the workspace allocate must be directly stored in the + * stack control block because it is later used in the free sequence. + * + * Thus it is the responsibility of the CPU dependent code to + * get and keep the stack adjust factor, the stack alignment, and + * the context initialization sequence in sync. + */ + + the_stack_size = _Stack_Adjust_size( the_stack_size ); + stack_addr = _Workspace_Allocate( the_stack_size ); + } + + if ( !stack_addr ) + the_stack_size = 0; + + the_thread->Start.stack = stack_addr; + + return the_stack_size; +} diff --git a/cpukit/score/src/threadstackfree.c b/cpukit/score/src/threadstackfree.c new file mode 100644 index 0000000000..64e0278e1b --- /dev/null +++ b/cpukit/score/src/threadstackfree.c @@ -0,0 +1,62 @@ +/* + * Thread Handler + * + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/apiext.h> +#include <rtems/score/context.h> +#include <rtems/score/interr.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/priority.h> +#include <rtems/score/states.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/userext.h> +#include <rtems/score/wkspace.h> +#include <rtems/config.h> + +/* + * _Thread_Stack_Free + * + * Deallocate the Thread's stack. + */ + +void _Thread_Stack_Free( + Thread_Control *the_thread +) +{ + #if defined(RTEMS_SCORE_THREAD_ENABLE_USER_PROVIDED_STACK_VIA_API) + /* + * If the API provided the stack space, then don't free it. + */ + if ( !the_thread->Start.core_allocated_stack ) + return; + #endif + + /* + * Call ONLY the CPU table stack free hook, or the + * the RTEMS workspace free. This is so the free + * routine properly matches the allocation of the stack. + */ + + if ( Configuration.stack_free_hook ) + (*Configuration.stack_free_hook)( the_thread->Start.Initial_stack.area ); + else + _Workspace_Free( the_thread->Start.Initial_stack.area ); +} diff --git a/cpukit/score/src/threadstart.c b/cpukit/score/src/threadstart.c new file mode 100644 index 0000000000..1bc293c96f --- /dev/null +++ b/cpukit/score/src/threadstart.c @@ -0,0 +1,69 @@ +/* + * Thread Handler + * + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/apiext.h> +#include <rtems/score/context.h> +#include <rtems/score/interr.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/priority.h> +#include <rtems/score/states.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/userext.h> +#include <rtems/score/wkspace.h> + +/* + * _Thread_Start + * + * DESCRIPTION: + * + * This routine initializes the executable information for a thread + * and makes it ready to execute. After this routine executes, the + * thread competes with all other threads for CPU time. + */ + +bool _Thread_Start( + Thread_Control *the_thread, + Thread_Start_types the_prototype, + void *entry_point, + void *pointer_argument, + Thread_Entry_numeric_type numeric_argument +) +{ + if ( _States_Is_dormant( the_thread->current_state ) ) { + + the_thread->Start.entry_point = (Thread_Entry) entry_point; + + the_thread->Start.prototype = the_prototype; + the_thread->Start.pointer_argument = pointer_argument; + the_thread->Start.numeric_argument = numeric_argument; + + _Thread_Load_environment( the_thread ); + + _Thread_Ready( the_thread ); + + _User_extensions_Thread_start( the_thread ); + + return true; + } + + return false; +} diff --git a/cpukit/score/src/threadstartmultitasking.c b/cpukit/score/src/threadstartmultitasking.c new file mode 100644 index 0000000000..efb2dae189 --- /dev/null +++ b/cpukit/score/src/threadstartmultitasking.c @@ -0,0 +1,91 @@ +/* + * Thread Handler + * + * + * COPYRIGHT (c) 1989-2006. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/apiext.h> +#include <rtems/score/context.h> +#include <rtems/score/interr.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/priority.h> +#include <rtems/score/states.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/userext.h> +#include <rtems/score/wkspace.h> + +/*PAGE + * + * _Thread_Start_multitasking + * + * This kernel routine readies the requested thread, the thread chain + * is adjusted. A new heir thread may be selected. + * + * Input parameters: + * system_thread - pointer to system initialization thread control block + * idle_thread - pointer to idle thread control block + * + * Output parameters: NONE + * + * NOTE: This routine uses the "blocking" heir selection mechanism. + * This ensures the correct heir after a thread restart. + * + * INTERRUPT LATENCY: + * ready chain + * select heir + */ + +void _Thread_Start_multitasking( void ) +{ + /* + * The system is now multitasking and completely initialized. + * This system thread now "hides" in a single processor until + * the system is shut down. + */ + + _System_state_Set( SYSTEM_STATE_UP ); + + _Thread_Dispatch_necessary = false; + + _Thread_Executing = _Thread_Heir; + + /* + * Get the init task(s) running. + * + * Note: Thread_Dispatch() is normally used to dispatch threads. As + * part of its work, Thread_Dispatch() restores floating point + * state for the heir task. + * + * This code avoids Thread_Dispatch(), and so we have to restore + * (actually initialize) the floating point state "by hand". + * + * Ignore the CPU_USE_DEFERRED_FP_SWITCH because we must always + * switch in the first thread if it is FP. + */ +#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) + /* + * don't need to worry about saving BSP's floating point state + */ + + if ( _Thread_Heir->fp_context != NULL ) + _Context_Restore_fp( &_Thread_Heir->fp_context ); +#endif + + _Context_Switch( &_Thread_BSP_context, &_Thread_Heir->Registers ); +} diff --git a/cpukit/score/src/threadtickletimeslice.c b/cpukit/score/src/threadtickletimeslice.c new file mode 100644 index 0000000000..50ded7f6a7 --- /dev/null +++ b/cpukit/score/src/threadtickletimeslice.c @@ -0,0 +1,105 @@ +/* + * Thread Handler + * + * + * COPYRIGHT (c) 1989-2009. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/apiext.h> +#include <rtems/score/context.h> +#include <rtems/score/interr.h> +#include <rtems/score/isr.h> +#include <rtems/score/object.h> +#include <rtems/score/priority.h> +#include <rtems/score/scheduler.h> +#include <rtems/score/states.h> +#include <rtems/score/sysstate.h> +#include <rtems/score/thread.h> +#include <rtems/score/threadq.h> +#include <rtems/score/userext.h> +#include <rtems/score/wkspace.h> + +/*PAGE + * + * _Thread_Tickle_timeslice + * + * This scheduler routine determines if timeslicing is enabled + * for the currently executing thread and, if so, updates the + * timeslice count and checks for timeslice expiration. + * + * Input parameters: NONE + * + * Output parameters: NONE + */ + +void _Thread_Tickle_timeslice( void ) +{ + Thread_Control *executing; + + executing = _Thread_Executing; + + #ifdef __RTEMS_USE_TICKS_FOR_STATISTICS__ + /* + * Increment the number of ticks this thread has been executing + */ + executing->cpu_time_used++; + #endif + + /* + * If the thread is not preemptible or is not ready, then + * just return. + */ + + if ( !executing->is_preemptible ) + return; + + if ( !_States_Is_ready( executing->current_state ) ) + return; + + /* + * The cpu budget algorithm determines what happens next. + */ + + switch ( executing->budget_algorithm ) { + case THREAD_CPU_BUDGET_ALGORITHM_NONE: + break; + + case THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE: + #if defined(RTEMS_SCORE_THREAD_ENABLE_EXHAUST_TIMESLICE) + case THREAD_CPU_BUDGET_ALGORITHM_EXHAUST_TIMESLICE: + #endif + if ( (int)(--executing->cpu_time_budget) <= 0 ) { + + /* + * A yield performs the ready chain mechanics needed when + * resetting a timeslice. If no other thread's are ready + * at the priority of the currently executing thread, then the + * executing thread's timeslice is reset. Otherwise, the + * currently executing thread is placed at the rear of the + * FIFO for this priority and a new heir is selected. + */ + _Scheduler_Yield( ); + executing->cpu_time_budget = _Thread_Ticks_per_timeslice; + } + break; + + #if defined(RTEMS_SCORE_THREAD_ENABLE_SCHEDULER_CALLOUT) + case THREAD_CPU_BUDGET_ALGORITHM_CALLOUT: + if ( --executing->cpu_time_budget == 0 ) + (*executing->budget_callout)( executing ); + break; + #endif + } +} diff --git a/cpukit/score/src/timespecaddto.c b/cpukit/score/src/timespecaddto.c new file mode 100644 index 0000000000..ac764b83c1 --- /dev/null +++ b/cpukit/score/src/timespecaddto.c @@ -0,0 +1,51 @@ +/** + * @file score/src/timespecaddto.c + */ + +/* + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <sys/types.h> +#include <rtems/score/timespec.h> +#include <rtems/score/tod.h> +#include <rtems/score/watchdog.h> + +/** + * + * This routines adds two timespecs. The second argument is added + * to the first. + */ + +uint32_t _Timespec_Add_to( + struct timespec *time, + const struct timespec *add +) +{ + uint32_t seconds = add->tv_sec; + + /* Add the basics */ + time->tv_sec += add->tv_sec; + time->tv_nsec += add->tv_nsec; + + /* Now adjust it so nanoseconds is in range */ + while ( time->tv_nsec >= TOD_NANOSECONDS_PER_SECOND ) { + time->tv_nsec -= TOD_NANOSECONDS_PER_SECOND; + time->tv_sec++; + seconds++; + } + + return seconds; +} diff --git a/cpukit/score/src/timespecdivide.c b/cpukit/score/src/timespecdivide.c new file mode 100644 index 0000000000..5e2cd2a65a --- /dev/null +++ b/cpukit/score/src/timespecdivide.c @@ -0,0 +1,59 @@ +/** + * @file score/src/timespecdivide.c + */ + +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <sys/types.h> +#include <rtems/score/timespec.h> +#include <rtems/score/tod.h> + +void _Timespec_Divide( + const struct timespec *lhs, + const struct timespec *rhs, + uint32_t *ival_percentage, + uint32_t *fval_percentage +) +{ + uint64_t left, right, answer; + + /* + * For math simplicity just convert the timespec to nanoseconds + * in a 64-bit integer. + */ + left = lhs->tv_sec * (uint64_t)TOD_NANOSECONDS_PER_SECOND; + left += lhs->tv_nsec; + right = rhs->tv_sec * (uint64_t)TOD_NANOSECONDS_PER_SECOND; + right += rhs->tv_nsec; + + if ( right == 0 ) { + *ival_percentage = 0; + *fval_percentage = 0; + return; + } + + /* + * Put it back in the timespec result. + * + * TODO: Rounding on the last digit of the fval. + */ + + answer = (left * 100000) / right; + + *ival_percentage = answer / 1000; + *fval_percentage = answer % 1000; +} diff --git a/cpukit/score/src/timespecdividebyinteger.c b/cpukit/score/src/timespecdividebyinteger.c new file mode 100644 index 0000000000..118fd24ee3 --- /dev/null +++ b/cpukit/score/src/timespecdividebyinteger.c @@ -0,0 +1,53 @@ +/** + * @file score/src/timespecdividebyinteger.c + */ + +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <sys/types.h> +#include <rtems/score/timespec.h> +#include <rtems/score/tod.h> + +void _Timespec_Divide_by_integer( + const struct timespec *time, + uint32_t iterations, + struct timespec *result +) +{ + uint64_t t; + + /* + * For math simplicity just convert the timespec to nanoseconds + * in a 64-bit integer. + */ + t = time->tv_sec; + t *= TOD_NANOSECONDS_PER_SECOND; + t += time->tv_nsec; + + /* + * Divide to get nanoseconds per iteration + */ + + t /= iterations; + + /* + * Put it back in the timespec result + */ + + result->tv_sec = t / TOD_NANOSECONDS_PER_SECOND; + result->tv_nsec = t % TOD_NANOSECONDS_PER_SECOND; +} diff --git a/cpukit/score/src/timespecfromticks.c b/cpukit/score/src/timespecfromticks.c new file mode 100644 index 0000000000..a3f44977fc --- /dev/null +++ b/cpukit/score/src/timespecfromticks.c @@ -0,0 +1,35 @@ +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <time.h> + +#include <rtems/system.h> +#include <rtems/config.h> +#include <rtems/score/timespec.h> +#include <rtems/score/tod.h> + +void _Timespec_From_ticks( + uint32_t ticks, + struct timespec *time +) +{ + uint32_t usecs; + + usecs = ticks * rtems_configuration_get_microseconds_per_tick(); + + time->tv_sec = usecs / TOD_MICROSECONDS_PER_SECOND; + time->tv_nsec = (usecs % TOD_MICROSECONDS_PER_SECOND) * + TOD_NANOSECONDS_PER_MICROSECOND; +} diff --git a/cpukit/score/src/timespecgreaterthan.c b/cpukit/score/src/timespecgreaterthan.c new file mode 100644 index 0000000000..b0e7870ac6 --- /dev/null +++ b/cpukit/score/src/timespecgreaterthan.c @@ -0,0 +1,42 @@ +/** + * @file score/src/timespecgreaterthan.c + */ + +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> + +#include <rtems/system.h> +#include <rtems/score/timespec.h> +#include <rtems/score/tod.h> + +bool _Timespec_Greater_than( + const struct timespec *lhs, + const struct timespec *rhs +) +{ + if ( lhs->tv_sec > rhs->tv_sec ) + return true; + + if ( lhs->tv_sec < rhs->tv_sec ) + return false; + + /* ASSERT: lhs->tv_sec == rhs->tv_sec */ + if ( lhs->tv_nsec > rhs->tv_nsec ) + return true; + + return false; +} diff --git a/cpukit/score/src/timespecisvalid.c b/cpukit/score/src/timespecisvalid.c new file mode 100644 index 0000000000..3347052ba9 --- /dev/null +++ b/cpukit/score/src/timespecisvalid.c @@ -0,0 +1,43 @@ +/** + * @file score/src/timespecisvalid.c + */ + +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> + +#include <rtems/system.h> +#include <rtems/score/timespec.h> +#include <rtems/score/tod.h> + +bool _Timespec_Is_valid( + const struct timespec *time +) +{ + if ( !time ) + return false; + + if ( time->tv_sec < 0 ) + return false; + + if ( time->tv_nsec < 0 ) + return false; + + if ( time->tv_nsec >= TOD_NANOSECONDS_PER_SECOND ) + return false; + + return true; +} diff --git a/cpukit/score/src/timespeclessthan.c b/cpukit/score/src/timespeclessthan.c new file mode 100644 index 0000000000..fb54e69dc9 --- /dev/null +++ b/cpukit/score/src/timespeclessthan.c @@ -0,0 +1,42 @@ +/** + * @file score/src/timespeclessthan.c + */ + +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> + +#include <rtems/system.h> +#include <rtems/score/timespec.h> +#include <rtems/score/tod.h> + +bool _Timespec_Less_than( + const struct timespec *lhs, + const struct timespec *rhs +) +{ + if ( lhs->tv_sec < rhs->tv_sec ) + return true; + + if ( lhs->tv_sec > rhs->tv_sec ) + return false; + + /* ASSERT: lhs->tv_sec == rhs->tv_sec */ + if ( lhs->tv_nsec < rhs->tv_nsec ) + return true; + + return false; +} diff --git a/cpukit/score/src/timespecsubtract.c b/cpukit/score/src/timespecsubtract.c new file mode 100644 index 0000000000..44e9f21c25 --- /dev/null +++ b/cpukit/score/src/timespecsubtract.c @@ -0,0 +1,41 @@ +/** + * @file score/src/timespecsubtract.c + */ + +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <sys/types.h> +#include <rtems/score/timespec.h> +#include <rtems/score/tod.h> +#include <rtems/score/watchdog.h> + +void _Timespec_Subtract( + const struct timespec *start, + const struct timespec *end, + struct timespec *result +) +{ + + if (end->tv_nsec < start->tv_nsec) { + result->tv_sec = end->tv_sec - start->tv_sec - 1; + result->tv_nsec = + (TOD_NANOSECONDS_PER_SECOND - start->tv_nsec) + end->tv_nsec; + } else { + result->tv_sec = end->tv_sec - start->tv_sec; + result->tv_nsec = end->tv_nsec - start->tv_nsec; + } +} diff --git a/cpukit/score/src/timespectoticks.c b/cpukit/score/src/timespectoticks.c new file mode 100644 index 0000000000..ddd82e67a7 --- /dev/null +++ b/cpukit/score/src/timespectoticks.c @@ -0,0 +1,50 @@ +/** + * @file score/src/timespectoticks.c + */ + +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> + +#include <rtems/system.h> +#include <rtems/config.h> +#include <rtems/score/timespec.h> +#include <rtems/score/tod.h> +#include <rtems/score/watchdog.h> + +/** + * + * This routines converts a timespec to the corresponding number of ticks. + */ + +uint32_t _Timespec_To_ticks( + const struct timespec *time +) +{ + uint32_t ticks; + + if ( (time->tv_sec == 0) && (time->tv_nsec == 0) ) + return 0; + + ticks = time->tv_sec * TOD_TICKS_PER_SECOND; + + ticks += time->tv_nsec / rtems_configuration_get_nanoseconds_per_tick(); + + if (ticks) + return ticks; + + return 1; +} diff --git a/cpukit/score/src/ts64addto.c b/cpukit/score/src/ts64addto.c new file mode 100644 index 0000000000..14439de0f3 --- /dev/null +++ b/cpukit/score/src/ts64addto.c @@ -0,0 +1,34 @@ +/** + * @file score/src/ts64addto.c +*/ + +/* + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> + +#include <rtems/system.h> +#include <rtems/score/timestamp.h> + +#if defined(CPU_RTEMS_SCORE_TIMESTAMP_IS_INT64) && \ + !defined(CPU_RTEMS_SCORE_TIMESTAMP_INT64_INLINE) +void _Timestamp64_Add_to( + Timestamp64_Control *_time, + Timestamp64_Control *_add +) +{ + *_time += *_add; +} +#endif diff --git a/cpukit/score/src/ts64divide.c b/cpukit/score/src/ts64divide.c new file mode 100644 index 0000000000..01e2661ac4 --- /dev/null +++ b/cpukit/score/src/ts64divide.c @@ -0,0 +1,52 @@ +/** + * @file score/src/ts64divide.c + */ + +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <sys/types.h> +#include <rtems/score/timestamp.h> + +/* This method is never inlined. */ +#if defined(CPU_RTEMS_SCORE_TIMESTAMP_IS_INT64) +void _Timestamp64_Divide( + const Timestamp64_Control *_lhs, + const Timestamp64_Control *_rhs, + uint32_t *_ival_percentage, + uint32_t *_fval_percentage +) +{ + Timestamp64_Control answer; + + if ( *_rhs == 0 ) { + *_ival_percentage = 0; + *_fval_percentage = 0; + return; + } + + /* + * This looks odd but gives the results the proper precision. + * + * TODO: Rounding on the last digit of the fval. + */ + + answer = (*_lhs * 100000) / *_rhs; + + *_ival_percentage = answer / 1000; + *_fval_percentage = answer % 1000; +} +#endif diff --git a/cpukit/score/src/ts64dividebyinteger.c b/cpukit/score/src/ts64dividebyinteger.c new file mode 100644 index 0000000000..f815078322 --- /dev/null +++ b/cpukit/score/src/ts64dividebyinteger.c @@ -0,0 +1,35 @@ +/** + * @file score/src/ts64dividebyinteger.c +*/ + +/* + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> + +#include <rtems/system.h> +#include <rtems/score/timestamp.h> + +#if defined(CPU_RTEMS_SCORE_TIMESTAMP_IS_INT64) && \ + !defined(CPU_RTEMS_SCORE_TIMESTAMP_INT64_INLINE) +void _Timestamp64_Divide_by_integer( + Timestamp64_Control *_time, + uint32_t _iterations, + Timestamp64_Control *_result +) +{ + *_result = *_time / _iterations; +} +#endif diff --git a/cpukit/score/src/ts64equalto.c b/cpukit/score/src/ts64equalto.c new file mode 100644 index 0000000000..d6c9eca998 --- /dev/null +++ b/cpukit/score/src/ts64equalto.c @@ -0,0 +1,34 @@ +/** + * @file score/src/ts64equalto.c +*/ + +/* + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> + +#include <rtems/system.h> +#include <rtems/score/timestamp.h> + +#if defined(CPU_RTEMS_SCORE_TIMESTAMP_IS_INT64) && \ + !defined(CPU_RTEMS_SCORE_TIMESTAMP_INT64_INLINE) +bool _Timestamp64_Equal_to( + Timestamp64_Control *_lhs, + Timestamp64_Control *_rhs +) +{ + return (*(_lhs) == *(_rhs)); +} +#endif diff --git a/cpukit/score/src/ts64getnanoseconds.c b/cpukit/score/src/ts64getnanoseconds.c new file mode 100644 index 0000000000..f9d57a9ab1 --- /dev/null +++ b/cpukit/score/src/ts64getnanoseconds.c @@ -0,0 +1,33 @@ +/** + * @file score/src/ts64toticks.c + */ + +/* + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> + +#include <rtems/system.h> +#include <rtems/score/timestamp.h> + +#if defined(CPU_RTEMS_SCORE_TIMESTAMP_IS_INT64) && \ + !defined(CPU_RTEMS_SCORE_TIMESTAMP_INT64_INLINE) +uint32_t _Timestamp64_Get_nanoseconds( + Timestamp64_Control *_time +) +{ + return *(_time) % 1000000000; +} +#endif diff --git a/cpukit/score/src/ts64getseconds.c b/cpukit/score/src/ts64getseconds.c new file mode 100644 index 0000000000..f459ee07a5 --- /dev/null +++ b/cpukit/score/src/ts64getseconds.c @@ -0,0 +1,33 @@ +/** + * @file score/src/ts64getseconds.c +*/ + +/* + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> + +#include <rtems/system.h> +#include <rtems/score/timestamp.h> + +#if defined(CPU_RTEMS_SCORE_TIMESTAMP_IS_INT64) && \ + !defined(CPU_RTEMS_SCORE_TIMESTAMP_INT64_INLINE) +uint32_t _Timestamp64_Get_seconds( + Timestamp64_Control *_time +) +{ + return *(_time) / 1000000000; +} +#endif diff --git a/cpukit/score/src/ts64greaterthan.c b/cpukit/score/src/ts64greaterthan.c new file mode 100644 index 0000000000..571adca4c1 --- /dev/null +++ b/cpukit/score/src/ts64greaterthan.c @@ -0,0 +1,34 @@ +/** + * @file score/src/ts64greaterthan.c +*/ + +/* + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> + +#include <rtems/system.h> +#include <rtems/score/timestamp.h> + +#if defined(CPU_RTEMS_SCORE_TIMESTAMP_IS_INT64) && \ + !defined(CPU_RTEMS_SCORE_TIMESTAMP_INT64_INLINE) +bool _Timestamp64_Greater_than( + Timestamp64_Control *_lhs, + Timestamp64_Control *_rhs +) +{ + return (*(_lhs) > *(_rhs)); +} +#endif diff --git a/cpukit/score/src/ts64lessthan.c b/cpukit/score/src/ts64lessthan.c new file mode 100644 index 0000000000..1df5eb11f8 --- /dev/null +++ b/cpukit/score/src/ts64lessthan.c @@ -0,0 +1,34 @@ +/** + * @file score/src/ts64lessthan.c +*/ + +/* + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> + +#include <rtems/system.h> +#include <rtems/score/timestamp.h> + +#if defined(CPU_RTEMS_SCORE_TIMESTAMP_IS_INT64) && \ + !defined(CPU_RTEMS_SCORE_TIMESTAMP_INT64_INLINE) +bool _Timestamp64_Less_than( + Timestamp64_Control *_lhs, + Timestamp64_Control *_rhs +) +{ + return (*(_lhs) < *(_rhs)); +} +#endif diff --git a/cpukit/score/src/ts64set.c b/cpukit/score/src/ts64set.c new file mode 100644 index 0000000000..f4ed3c40e7 --- /dev/null +++ b/cpukit/score/src/ts64set.c @@ -0,0 +1,39 @@ +/** + * @file score/src/ts64set.c +*/ + +/* + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> + +#include <rtems/system.h> +#include <rtems/score/timestamp.h> + +#if defined(CPU_RTEMS_SCORE_TIMESTAMP_IS_INT64) && \ + !defined(CPU_RTEMS_SCORE_TIMESTAMP_INT64_INLINE) +void _Timestamp64_Set( + Timestamp64_Control *_time, + long _seconds, + long _nanoseconds +) +{ + int64_t time; + + time = (int64_t)_seconds * 1000000000; + time += (int64_t)_nanoseconds; + *_time = time; +} +#endif diff --git a/cpukit/score/src/ts64settozero.c b/cpukit/score/src/ts64settozero.c new file mode 100644 index 0000000000..f5cd78194d --- /dev/null +++ b/cpukit/score/src/ts64settozero.c @@ -0,0 +1,33 @@ +/** + * @file score/src/ts64settozero.c +*/ + +/* + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> + +#include <rtems/system.h> +#include <rtems/score/timestamp.h> + +#if defined(CPU_RTEMS_SCORE_TIMESTAMP_IS_INT64) && \ + !defined(CPU_RTEMS_SCORE_TIMESTAMP_INT64_INLINE) +void _Timestamp64_Set_to_zero( + Timestamp64_Control *_time +) +{ + *_time = 0; +} +#endif diff --git a/cpukit/score/src/ts64subtract.c b/cpukit/score/src/ts64subtract.c new file mode 100644 index 0000000000..be7445b2e6 --- /dev/null +++ b/cpukit/score/src/ts64subtract.c @@ -0,0 +1,35 @@ +/** + * @file score/src/ts64subtract.c +*/ + +/* + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> + +#include <rtems/system.h> +#include <rtems/score/timestamp.h> + +#if defined(CPU_RTEMS_SCORE_TIMESTAMP_IS_INT64) && \ + !defined(CPU_RTEMS_SCORE_TIMESTAMP_INT64_INLINE) +void _Timestamp64_Subtract( + Timestamp64_Control *_start, + Timestamp64_Control *_end, + Timestamp64_Control *_result +) +{ + *_result = *_end - *_start; +} +#endif diff --git a/cpukit/score/src/ts64toticks.c b/cpukit/score/src/ts64toticks.c new file mode 100644 index 0000000000..273bcc15b4 --- /dev/null +++ b/cpukit/score/src/ts64toticks.c @@ -0,0 +1,40 @@ +/** + * @file score/src/ts64toticks.c + */ + +/* + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> + +#include <rtems/system.h> +#include <rtems/config.h> +#include <rtems/score/timestamp.h> +#include <rtems/score/tod.h> + +#if defined(CPU_RTEMS_SCORE_TIMESTAMP_IS_INT64) && \ + !defined(CPU_RTEMS_SCORE_TIMESTAMP_INT64_INLINE) +uint32_t _Timestamp64_To_ticks( + const Timestamp64_Control *time +) +{ + uint32_t ticks; + + ticks = *time / rtems_configuration_get_nanoseconds_per_tick(); + if ( ticks ) + return ticks; + return 1; +} +#endif diff --git a/cpukit/score/src/ts64totimespec.c b/cpukit/score/src/ts64totimespec.c new file mode 100644 index 0000000000..92c2b690bc --- /dev/null +++ b/cpukit/score/src/ts64totimespec.c @@ -0,0 +1,35 @@ +/** + * @file score/src/ts64totimespec.c +*/ + +/* + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> + +#include <rtems/system.h> +#include <rtems/score/timestamp.h> + +#if defined(CPU_RTEMS_SCORE_TIMESTAMP_IS_INT64) && \ + !defined(CPU_RTEMS_SCORE_TIMESTAMP_INT64_INLINE) +void _Timestamp64_To_timespec( + Timestamp64_Control *_timestamp, + struct timespec *_timespec +) +{ + _timespec->tv_sec = *_timestamp / 1000000000; + _timespec->tv_nsec = *_timestamp % 1000000000; +} +#endif diff --git a/cpukit/score/src/userext.c b/cpukit/score/src/userext.c new file mode 100644 index 0000000000..d0e8efc6c9 --- /dev/null +++ b/cpukit/score/src/userext.c @@ -0,0 +1,61 @@ +/** + * @file + * + * @ingroup ScoreUserExt + * + * @brief User Extension Handler implementation. + */ + +/* + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/config.h> +#include <rtems/score/userext.h> +#include <rtems/score/wkspace.h> +#include <string.h> + +void _User_extensions_Handler_initialization(void) +{ + User_extensions_Control *extension; + uint32_t i; + uint32_t number_of_extensions; + User_extensions_Table *initial_extensions; + + number_of_extensions = Configuration.number_of_initial_extensions; + initial_extensions = Configuration.User_extension_table; + + _Chain_Initialize_empty( &_User_extensions_List ); + _Chain_Initialize_empty( &_User_extensions_Switches_list ); + + if ( initial_extensions ) { + extension = (User_extensions_Control *) + _Workspace_Allocate_or_fatal_error( + number_of_extensions * sizeof( User_extensions_Control ) + ); + + memset ( + extension, + 0, + number_of_extensions * sizeof( User_extensions_Control ) + ); + + for ( i = 0 ; i < number_of_extensions ; i++ ) { + _User_extensions_Add_set_with_table (extension, &initial_extensions[i]); + extension++; + } + } +} + diff --git a/cpukit/score/src/userextaddset.c b/cpukit/score/src/userextaddset.c new file mode 100644 index 0000000000..fd732e73c4 --- /dev/null +++ b/cpukit/score/src/userextaddset.c @@ -0,0 +1,45 @@ +/** + * @file + * + * @ingroup ScoreUserExt + * + * @brief User Extension Handler implementation. + */ + +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/userext.h> + +void _User_extensions_Add_set( + User_extensions_Control *the_extension +) +{ + _Chain_Append( &_User_extensions_List, &the_extension->Node ); + + /* + * If a switch handler is present, append it to the switch chain. + */ + + if ( the_extension->Callouts.thread_switch != NULL ) { + the_extension->Switch.thread_switch = + the_extension->Callouts.thread_switch; + _Chain_Append( + &_User_extensions_Switches_list, + &the_extension->Switch.Node + ); + } +} diff --git a/cpukit/score/src/userextremoveset.c b/cpukit/score/src/userextremoveset.c new file mode 100644 index 0000000000..a7f23da536 --- /dev/null +++ b/cpukit/score/src/userextremoveset.c @@ -0,0 +1,39 @@ +/** + * @file + * + * @ingroup ScoreUserExt + * + * @brief User Extension Handler implementation. + */ + +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/userext.h> + +void _User_extensions_Remove_set ( + User_extensions_Control *the_extension +) +{ + _Chain_Extract( &the_extension->Node ); + + /* + * If a switch handler is present, remove it. + */ + + if ( the_extension->Callouts.thread_switch != NULL ) + _Chain_Extract( &the_extension->Switch.Node ); +} diff --git a/cpukit/score/src/userextthreadbegin.c b/cpukit/score/src/userextthreadbegin.c new file mode 100644 index 0000000000..9fed82ac4a --- /dev/null +++ b/cpukit/score/src/userextthreadbegin.c @@ -0,0 +1,81 @@ +/** + * @file + * + * @ingroup ScoreUserExt + * + * @brief User Extension Handler implementation. + */ + +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/userext.h> + +void _User_extensions_Thread_begin ( + Thread_Control *executing +) +{ + Chain_Node *the_node; + User_extensions_Control *the_extension; + + for ( the_node = _Chain_First( &_User_extensions_List ); + !_Chain_Is_tail( &_User_extensions_List, the_node ) ; + the_node = the_node->next ) { + + the_extension = (User_extensions_Control *) the_node; + + if ( the_extension->Callouts.thread_begin != NULL ) + (*the_extension->Callouts.thread_begin)( executing ); + } +} + +void _User_extensions_Thread_exitted ( + Thread_Control *executing +) +{ + Chain_Node *the_node; + User_extensions_Control *the_extension; + + for ( the_node = _Chain_Last( &_User_extensions_List ); + !_Chain_Is_head( &_User_extensions_List, the_node ) ; + the_node = the_node->previous ) { + + the_extension = (User_extensions_Control *) the_node; + + if ( the_extension->Callouts.thread_exitted != NULL ) + (*the_extension->Callouts.thread_exitted)( executing ); + } +} + +void _User_extensions_Fatal ( + Internal_errors_Source the_source, + bool is_internal, + Internal_errors_t the_error +) +{ + Chain_Node *the_node; + User_extensions_Control *the_extension; + + for ( the_node = _Chain_Last( &_User_extensions_List ); + !_Chain_Is_head( &_User_extensions_List, the_node ) ; + the_node = the_node->previous ) { + + the_extension = (User_extensions_Control *) the_node; + + if ( the_extension->Callouts.fatal != NULL ) + (*the_extension->Callouts.fatal)( the_source, is_internal, the_error ); + } +} diff --git a/cpukit/score/src/userextthreadcreate.c b/cpukit/score/src/userextthreadcreate.c new file mode 100644 index 0000000000..a2950ee37e --- /dev/null +++ b/cpukit/score/src/userextthreadcreate.c @@ -0,0 +1,52 @@ +/** + * @file + * + * @ingroup ScoreUserExt + * + * @brief User Extension Handler implementation. + */ + +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/userext.h> + +bool _User_extensions_Thread_create ( + Thread_Control *the_thread +) +{ + Chain_Node *the_node; + User_extensions_Control *the_extension; + bool status; + + for ( the_node = _Chain_First( &_User_extensions_List ); + !_Chain_Is_tail( &_User_extensions_List, the_node ) ; + the_node = the_node->next ) { + + the_extension = (User_extensions_Control *) the_node; + + if ( the_extension->Callouts.thread_create != NULL ) { + status = (*the_extension->Callouts.thread_create)( + _Thread_Executing, + the_thread + ); + if ( !status ) + return false; + } + } + + return true; +} diff --git a/cpukit/score/src/userextthreaddelete.c b/cpukit/score/src/userextthreaddelete.c new file mode 100644 index 0000000000..39397fea84 --- /dev/null +++ b/cpukit/score/src/userextthreaddelete.c @@ -0,0 +1,46 @@ +/** + * @file + * + * @ingroup ScoreUserExt + * + * @brief User Extension Handler implementation. + */ + +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/userext.h> + +void _User_extensions_Thread_delete ( + Thread_Control *the_thread +) +{ + Chain_Node *the_node; + User_extensions_Control *the_extension; + + for ( the_node = _Chain_Last( &_User_extensions_List ); + !_Chain_Is_head( &_User_extensions_List, the_node ) ; + the_node = the_node->previous ) { + + the_extension = (User_extensions_Control *) the_node; + + if ( the_extension->Callouts.thread_delete != NULL ) + (*the_extension->Callouts.thread_delete)( + _Thread_Executing, + the_thread + ); + } +} diff --git a/cpukit/score/src/userextthreadrestart.c b/cpukit/score/src/userextthreadrestart.c new file mode 100644 index 0000000000..c2a4d69e6a --- /dev/null +++ b/cpukit/score/src/userextthreadrestart.c @@ -0,0 +1,46 @@ +/** + * @file + * + * @ingroup ScoreUserExt + * + * @brief User Extension Handler implementation. + */ + +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/userext.h> + +void _User_extensions_Thread_restart ( + Thread_Control *the_thread +) +{ + Chain_Node *the_node; + User_extensions_Control *the_extension; + + for ( the_node = _Chain_First( &_User_extensions_List ); + !_Chain_Is_tail( &_User_extensions_List, the_node ) ; + the_node = the_node->next ) { + + the_extension = (User_extensions_Control *) the_node; + + if ( the_extension->Callouts.thread_restart != NULL ) + (*the_extension->Callouts.thread_restart)( + _Thread_Executing, + the_thread + ); + } +} diff --git a/cpukit/score/src/userextthreadstart.c b/cpukit/score/src/userextthreadstart.c new file mode 100644 index 0000000000..0fbe6ab755 --- /dev/null +++ b/cpukit/score/src/userextthreadstart.c @@ -0,0 +1,46 @@ +/** + * @file + * + * @ingroup ScoreUserExt + * + * @brief User Extension Handler implementation. + */ + +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/userext.h> + +void _User_extensions_Thread_start ( + Thread_Control *the_thread +) +{ + Chain_Node *the_node; + User_extensions_Control *the_extension; + + for ( the_node = _Chain_First( &_User_extensions_List ); + !_Chain_Is_tail( &_User_extensions_List, the_node ) ; + the_node = the_node->next ) { + + the_extension = (User_extensions_Control *) the_node; + + if ( the_extension->Callouts.thread_start != NULL ) + (*the_extension->Callouts.thread_start)( + _Thread_Executing, + the_thread + ); + } +} diff --git a/cpukit/score/src/userextthreadswitch.c b/cpukit/score/src/userextthreadswitch.c new file mode 100644 index 0000000000..026b56d9de --- /dev/null +++ b/cpukit/score/src/userextthreadswitch.c @@ -0,0 +1,43 @@ +/** + * @file + * + * @ingroup ScoreUserExt + * + * @brief User Extension Handler implementation. + */ + +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/userext.h> + +void _User_extensions_Thread_switch ( + Thread_Control *executing, + Thread_Control *heir +) +{ + Chain_Node *the_node; + User_extensions_Switch_control *the_extension_switch; + + for ( the_node = _Chain_First( &_User_extensions_Switches_list ); + !_Chain_Is_tail( &_User_extensions_Switches_list, the_node ) ; + the_node = the_node->next ) { + + the_extension_switch = (User_extensions_Switch_control *) the_node; + + (*the_extension_switch->thread_switch)( executing, heir ); + } +} diff --git a/cpukit/score/src/watchdog.c b/cpukit/score/src/watchdog.c new file mode 100644 index 0000000000..591f2de117 --- /dev/null +++ b/cpukit/score/src/watchdog.c @@ -0,0 +1,42 @@ +/* + * Watchdog Handler + * + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/watchdog.h> + +/*PAGE + * + * _Watchdog_Handler_initialization + * + * This routine initializes the watchdog handler. + * + * Input parameters: NONE + * + * Output parameters: NONE + */ + +void _Watchdog_Handler_initialization( void ) +{ + _Watchdog_Sync_count = 0; + _Watchdog_Sync_level = 0; + _Watchdog_Ticks_since_boot = 0; + + _Chain_Initialize_empty( &_Watchdog_Ticks_chain ); + _Chain_Initialize_empty( &_Watchdog_Seconds_chain ); +} diff --git a/cpukit/score/src/watchdogadjust.c b/cpukit/score/src/watchdogadjust.c new file mode 100644 index 0000000000..89d4859906 --- /dev/null +++ b/cpukit/score/src/watchdogadjust.c @@ -0,0 +1,87 @@ +/* + * Watchdog Handler + * + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/watchdog.h> + +/*PAGE + * + * _Watchdog_Adjust + * + * This routine adjusts the delta chain backward or forward in response + * to a time change. + * + * Input parameters: + * header - pointer to the delta chain to be adjusted + * direction - forward or backward adjustment to delta chain + * units - units to adjust + * + * Output parameters: + */ + +void _Watchdog_Adjust( + Chain_Control *header, + Watchdog_Adjust_directions direction, + Watchdog_Interval units +) +{ + ISR_Level level; + + _ISR_Disable( level ); + + /* + * NOTE: It is safe NOT to make 'header' a pointer + * to volatile data (contrast this with watchdoginsert.c) + * because we call _Watchdog_Tickle() below and + * hence the compiler must not assume *header to remain + * unmodified across that call. + * + * Till Straumann, 7/2003 + */ + if ( !_Chain_Is_empty( header ) ) { + switch ( direction ) { + case WATCHDOG_BACKWARD: + _Watchdog_First( header )->delta_interval += units; + break; + case WATCHDOG_FORWARD: + while ( units ) { + if ( units < _Watchdog_First( header )->delta_interval ) { + _Watchdog_First( header )->delta_interval -= units; + break; + } else { + units -= _Watchdog_First( header )->delta_interval; + _Watchdog_First( header )->delta_interval = 1; + + _ISR_Enable( level ); + + _Watchdog_Tickle( header ); + + _ISR_Disable( level ); + + if ( _Chain_Is_empty( header ) ) + break; + } + } + break; + } + } + + _ISR_Enable( level ); + +} diff --git a/cpukit/score/src/watchdogadjusttochain.c b/cpukit/score/src/watchdogadjusttochain.c new file mode 100644 index 0000000000..569a9364f7 --- /dev/null +++ b/cpukit/score/src/watchdogadjusttochain.c @@ -0,0 +1,83 @@ +/** + * @file watchdogadjusttochain.c + * + * This is used by the Timer Server task. + */ + +/* COPYRIGHT (c) 1989-2009. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/watchdog.h> + +void _Watchdog_Adjust_to_chain( + Chain_Control *header, + Watchdog_Interval units_arg, + Chain_Control *to_fire + +) +{ + Watchdog_Interval units = units_arg; + ISR_Level level; + Watchdog_Control *first; + + if ( units <= 0 ) { + return; + } + + _ISR_Disable( level ); + + while ( 1 ) { + if ( units <= 0 ) { + break; + } + if ( _Chain_Is_empty( header ) ) { + break; + } + first = _Watchdog_First( header ); + + /* + * If it is longer than "units" until the first element on the chain + * fires, then bump it and quit. + */ + if ( units < first->delta_interval ) { + first->delta_interval -= units; + break; + } + + /* + * The first set happens in less than units, so take all of them + * off the chain and adjust units to reflect this. + */ + units -= first->delta_interval; + first->delta_interval = 0; + + while ( 1 ) { + _Chain_Extract_unprotected( &first->Node ); + _Chain_Append_unprotected( to_fire, &first->Node ); + + _ISR_Flash( level ); + + if ( _Chain_Is_empty( header ) ) + break; + first = _Watchdog_First( header ); + if ( first->delta_interval != 0 ) + break; + } + } + + _ISR_Enable( level ); +} + diff --git a/cpukit/score/src/watchdoginsert.c b/cpukit/score/src/watchdoginsert.c new file mode 100644 index 0000000000..e4b86bd271 --- /dev/null +++ b/cpukit/score/src/watchdoginsert.c @@ -0,0 +1,100 @@ +/* + * Watchdog Handler + * + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/watchdog.h> + +/*PAGE + * + * _Watchdog_Insert + * + * This routine inserts a watchdog timer on to the appropriate delta + * chain while updating the delta interval counters. + */ + +void _Watchdog_Insert( + Chain_Control *header, + Watchdog_Control *the_watchdog +) +{ + ISR_Level level; + Watchdog_Control *after; + uint32_t insert_isr_nest_level; + Watchdog_Interval delta_interval; + + + insert_isr_nest_level = _ISR_Nest_level; + + _ISR_Disable( level ); + + /* + * Check to see if the watchdog has just been inserted by a + * higher priority interrupt. If so, abandon this insert. + */ + + if ( the_watchdog->state != WATCHDOG_INACTIVE ) { + _ISR_Enable( level ); + return; + } + + the_watchdog->state = WATCHDOG_BEING_INSERTED; + _Watchdog_Sync_count++; + +restart: + delta_interval = the_watchdog->initial; + + for ( after = _Watchdog_First( header ) ; + ; + after = _Watchdog_Next( after ) ) { + + if ( delta_interval == 0 || !_Watchdog_Next( after ) ) + break; + + if ( delta_interval < after->delta_interval ) { + after->delta_interval -= delta_interval; + break; + } + + delta_interval -= after->delta_interval; + + _ISR_Flash( level ); + + if ( the_watchdog->state != WATCHDOG_BEING_INSERTED ) { + goto exit_insert; + } + + if ( _Watchdog_Sync_level > insert_isr_nest_level ) { + _Watchdog_Sync_level = insert_isr_nest_level; + goto restart; + } + } + + _Watchdog_Activate( the_watchdog ); + + the_watchdog->delta_interval = delta_interval; + + _Chain_Insert_unprotected( after->Node.previous, &the_watchdog->Node ); + + the_watchdog->start_time = _Watchdog_Ticks_since_boot; + +exit_insert: + _Watchdog_Sync_level = insert_isr_nest_level; + _Watchdog_Sync_count--; + _ISR_Enable( level ); +} diff --git a/cpukit/score/src/watchdognanoseconds.c b/cpukit/score/src/watchdognanoseconds.c new file mode 100644 index 0000000000..b3d3e7b028 --- /dev/null +++ b/cpukit/score/src/watchdognanoseconds.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2010 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/watchdog.h> + +Watchdog_Nanoseconds_since_last_tick_routine + _Watchdog_Nanoseconds_since_tick_handler = + _Watchdog_Nanoseconds_since_tick_default_handler; + +uint32_t _Watchdog_Nanoseconds_since_tick_default_handler( void ) +{ + return 0; +} diff --git a/cpukit/score/src/watchdogremove.c b/cpukit/score/src/watchdogremove.c new file mode 100644 index 0000000000..3ce3367657 --- /dev/null +++ b/cpukit/score/src/watchdogremove.c @@ -0,0 +1,73 @@ +/* + * Watchdog Handler + * + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/watchdog.h> + +/*PAGE + * + * _Watchdog_Remove + * + * The routine removes a watchdog from a delta chain and updates + * the delta counters of the remaining watchdogs. + */ + +Watchdog_States _Watchdog_Remove( + Watchdog_Control *the_watchdog +) +{ + ISR_Level level; + Watchdog_States previous_state; + Watchdog_Control *next_watchdog; + + _ISR_Disable( level ); + previous_state = the_watchdog->state; + switch ( previous_state ) { + case WATCHDOG_INACTIVE: + break; + + case WATCHDOG_BEING_INSERTED: + + /* + * It is not actually on the chain so just change the state and + * the Insert operation we interrupted will be aborted. + */ + the_watchdog->state = WATCHDOG_INACTIVE; + break; + + case WATCHDOG_ACTIVE: + case WATCHDOG_REMOVE_IT: + + the_watchdog->state = WATCHDOG_INACTIVE; + next_watchdog = _Watchdog_Next( the_watchdog ); + + if ( _Watchdog_Next(next_watchdog) ) + next_watchdog->delta_interval += the_watchdog->delta_interval; + + if ( _Watchdog_Sync_count ) + _Watchdog_Sync_level = _ISR_Nest_level; + + _Chain_Extract_unprotected( &the_watchdog->Node ); + break; + } + the_watchdog->stop_time = _Watchdog_Ticks_since_boot; + + _ISR_Enable( level ); + return( previous_state ); +} diff --git a/cpukit/score/src/watchdogreport.c b/cpukit/score/src/watchdogreport.c new file mode 100644 index 0000000000..58bce56959 --- /dev/null +++ b/cpukit/score/src/watchdogreport.c @@ -0,0 +1,41 @@ +/** + * @file watchdogreport.c + * + * This should only be used for debugging. + */ + +/* COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/watchdog.h> +#include <rtems/bspIo.h> + +void _Watchdog_Report( + const char *name, + Watchdog_Control *watch +) +{ + printk( + "%s%s%4d %5d %p %p 0x%08x %p\n", + ((name) ? name : ""), + ((name) ? " " : ""), + watch->delta_interval, + watch->initial, + watch, + watch->routine, + watch->id, + watch->user_data + ); +} diff --git a/cpukit/score/src/watchdogreportchain.c b/cpukit/score/src/watchdogreportchain.c new file mode 100644 index 0000000000..8b616914c6 --- /dev/null +++ b/cpukit/score/src/watchdogreportchain.c @@ -0,0 +1,50 @@ +/** + * @file watchdogreportchain.c + * + * This should only be used for debugging. + */ + +/* COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/watchdog.h> +#include <rtems/score/isr.h> +#include <rtems/bspIo.h> + +void _Watchdog_Report_chain( + const char *name, + Chain_Control *header +) +{ + ISR_Level level; + Chain_Node *node; + + _ISR_Disable( level ); + printk( "Watchdog Chain: %s %p\n", name, header ); + if ( !_Chain_Is_empty( header ) ) { + for ( node = _Chain_First( header ) ; + node != _Chain_Tail(header) ; + node = node->next ) + { + Watchdog_Control *watch = (Watchdog_Control *) node; + + _Watchdog_Report( NULL, watch ); + } + printk( "== end of %s \n", name ); + } else { + printk( "Chain is empty\n" ); + } + _ISR_Enable( level ); +} diff --git a/cpukit/score/src/watchdogtickle.c b/cpukit/score/src/watchdogtickle.c new file mode 100644 index 0000000000..09b3c7bf09 --- /dev/null +++ b/cpukit/score/src/watchdogtickle.c @@ -0,0 +1,129 @@ +/* + * Watchdog Handler + * + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/watchdog.h> + +/*PAGE + * + * _Watchdog_Tickle + * + * This routine decrements the delta counter in response to a tick. The + * delta chain is updated accordingly. + * + * Input parameters: + * header - pointer to the delta chain to be tickled + * + * Output parameters: NONE + */ + +void _Watchdog_Tickle( + Chain_Control *header +) +{ + ISR_Level level; + Watchdog_Control *the_watchdog; + Watchdog_States watchdog_state; + + /* + * See the comment in watchdoginsert.c and watchdogadjust.c + * about why it's safe not to declare header a pointer to + * volatile data - till, 2003/7 + */ + + _ISR_Disable( level ); + + if ( _Chain_Is_empty( header ) ) + goto leave; + + the_watchdog = _Watchdog_First( header ); + + /* + * For some reason, on rare occasions the_watchdog->delta_interval + * of the head of the watchdog chain is 0. Before this test was + * added, on these occasions an event (which usually was supposed + * to have a timeout of 1 tick would have a delta_interval of 0, which + * would be decremented to 0xFFFFFFFF by the unprotected + * "the_watchdog->delta_interval--;" operation. + * This would mean the event would not timeout, and also the chain would + * be blocked, because a timeout with a very high number would be at the + * head, rather than at the end. + * The test "if (the_watchdog->delta_interval != 0)" + * here prevents this from occuring. + * + * We were not able to categorically identify the situation that causes + * this, but proved it to be true empirically. So this check causes + * correct behaviour in this circumstance. + * + * The belief is that a race condition exists whereby an event at the head + * of the chain is removed (by a pending ISR or higher priority task) + * during the _ISR_Flash( level ); in _Watchdog_Insert, but the watchdog + * to be inserted has already had its delta_interval adjusted to 0, and + * so is added to the head of the chain with a delta_interval of 0. + * + * Steven Johnson - 12/2005 (gcc-3.2.3 -O3 on powerpc) + */ + if (the_watchdog->delta_interval != 0) { + the_watchdog->delta_interval--; + if ( the_watchdog->delta_interval != 0 ) + goto leave; + } + + do { + watchdog_state = _Watchdog_Remove( the_watchdog ); + + _ISR_Enable( level ); + + switch( watchdog_state ) { + case WATCHDOG_ACTIVE: + (*the_watchdog->routine)( + the_watchdog->id, + the_watchdog->user_data + ); + break; + + case WATCHDOG_INACTIVE: + /* + * This state indicates that the watchdog is not on any chain. + * Thus, it is NOT on a chain being tickled. This case should + * never occur. + */ + break; + + case WATCHDOG_BEING_INSERTED: + /* + * This state indicates that the watchdog is in the process of + * BEING inserted on the chain. Thus, it can NOT be on a chain + * being tickled. This case should never occur. + */ + break; + + case WATCHDOG_REMOVE_IT: + break; + } + + _ISR_Disable( level ); + + the_watchdog = _Watchdog_First( header ); + } while ( !_Chain_Is_empty( header ) && + (the_watchdog->delta_interval == 0) ); + +leave: + _ISR_Enable(level); +} diff --git a/cpukit/score/src/wkspace.c b/cpukit/score/src/wkspace.c new file mode 100644 index 0000000000..568bfc1ce7 --- /dev/null +++ b/cpukit/score/src/wkspace.c @@ -0,0 +1,125 @@ +/* + * Workspace Handler + * + * COPYRIGHT (c) 1989-2009. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/system.h> +#include <rtems/config.h> +#include <rtems/score/wkspace.h> +#include <rtems/score/interr.h> + +#include <string.h> /* for memset */ + +/* #define DEBUG_WORKSPACE */ +#if defined(DEBUG_WORKSPACE) + #include <rtems/bspIo.h> +#endif + +/* + * _Workspace_Handler_initialization + */ +void _Workspace_Handler_initialization(void) +{ + uintptr_t memory_available = 0; + void *starting_address = Configuration.work_space_start; + uintptr_t size = Configuration.work_space_size; + + if ( Configuration.do_zero_of_workspace ) + memset( starting_address, 0, size ); + + memory_available = _Heap_Initialize( + &_Workspace_Area, + starting_address, + size, + CPU_HEAP_ALIGNMENT + ); + + if ( memory_available == 0 ) + _Internal_error_Occurred( + INTERNAL_ERROR_CORE, + true, + INTERNAL_ERROR_TOO_LITTLE_WORKSPACE + ); +} + +/* + * _Workspace_Allocate + */ +void *_Workspace_Allocate( + size_t size +) +{ + void *memory; + + memory = _Heap_Allocate( &_Workspace_Area, size ); + #if defined(DEBUG_WORKSPACE) + printk( + "Workspace_Allocate(%d) from %p/%p -> %p\n", + size, + __builtin_return_address( 0 ), + __builtin_return_address( 1 ), + memory + ); + #endif + return memory; +} + +/* + * _Workspace_Free + */ +void _Workspace_Free( + void *block +) +{ + #if defined(DEBUG_WORKSPACE) + printk( + "Workspace_Free(%p) from %p/%p\n", + block, + __builtin_return_address( 0 ), + __builtin_return_address( 1 ) + ); + #endif + _Heap_Free( &_Workspace_Area, block ); +} + +/* + * _Workspace_Allocate_or_fatal_error + */ +void *_Workspace_Allocate_or_fatal_error( + size_t size +) +{ + void *memory; + + memory = _Heap_Allocate( &_Workspace_Area, size ); + #if defined(DEBUG_WORKSPACE) + printk( + "Workspace_Allocate_or_fatal_error(%d) from %p/%p -> %p\n", + size, + __builtin_return_address( 0 ), + __builtin_return_address( 1 ), + memory + ); + #endif + + if ( memory == NULL ) + _Internal_error_Occurred( + INTERNAL_ERROR_CORE, + true, + INTERNAL_ERROR_WORKSPACE_ALLOCATION + ); + + return memory; +} |