Академический Документы
Профессиональный Документы
Культура Документы
.. Página Web:
.. http://atc1.aut.alcala.es/~infind
.. e-mail: david.jurado@uah.es
.. Despacho: E-232
Departamento de Automática
Práctica 4
Listas doblemente
enlazadas
. . . . . . . . .
Laboraratorio de Informática
Industrial II
Laboratorio de Informática Industrial II Departamento de Automática.
..
..
..
..
..
Listas de datos
Desarrollo de la práctica
En esta práctica se entrega un único archivo de código en lenguaje C que contiene
una implementación de listas. También se acompaña de algunas funciones
encargadas de informar sobre errores.
Téngase en cuenta la estructura de las funciones en las que existe una primera
parte encargada de la comprobación de errores, que aborta la ejecución de las
mismas si no se pueden satisfacer sus objetivos.
Objetivo
Se pretende optimizar el programa para poder utilizarlo desde un
microcontrolador. Además se desea hacerlo modular para poder reutilizar el
código de información de errores. Para esto será necesario analizar detenidamente
el código.
A Hacer
Para optimizar se ha optado por que se cree sólo una lista global de tipo
list_static_nodes en lugar de listas locales. Las funciones que la reciben
ahora como argumento, deben ser reconvertidas para que tomen implícitamente el
ejemplar global.
2
Filtros I: Convolución y FIR David Jurado González
Crear un proyecto de tipo consola que incorpore todos estos archivos y generar el
ejecutable. El programa resultante debe tener la misma apariencia que el original.
Cuestiones
• ¿Qué hace el programa?
. . .
#ifndef __LIST_H__
#define __LIST_H__
. . .
#endif // __LIST_H__
¿Por qué se hace esto? Añadir un código similar a todos los archivos de cabecera
de acuerdo a sus respectivos nombres.
3
..
..
..
..
/** \file ListaEnlazada.cpp
* \author David Jurado González.
.. NS_RUNNING,
NS_WAITING,
NS_STOPPED,
///<
///<
///<
En ejecución.
En espera.
Detenido.
* \brief Ejemplo del uso de listas doblemente enlazadas. NS_LAST ///< Último valor usado en la enumeración.
* Código para facilitar el aprendizaje de Sistemas Operativos de Tiempo Real. };
* Se crea el entorno necesario para poder implementar un núcleo que gestione
* tareas en listas con 5 prioridades posibles, para ser ejecutada cada una con /// Prioridad del hilo.
* el algoritmo de Round Robin. enum node_priority
*/ {
#include <stdio.h> NP_NONE = 0, ///< Sin prioridad asignada.
#include <memory.h> NP_IDLE, ///< Muy baja.
NP_LOW, ///< Baja.
/// Tipo de datos para valor de retorno de funcinones. NP_NORMAL, ///< Normal.
#define HRESULT short NP_HIGH, ///< Alta.
NP_RT, ///< Tiempo Real.
/** \brief Macro para determinar si una función ha fallado. NP_LAST ///< Último valor usado en la enumeración.
En \a hr el código de retorno de la función. */ };
#define FAILED(hr) (hr & 0x8000)
typedef unsigned char priority_t, ///< Tipo para almacenar la prioridad de un hilo.
/** \brief Macro para determinar si una función se ha ejecutado correctamente. state_t; ///< Tipo para almacenar el estado de un hilo.
En \a hr el código de retorno de la función. */
#define SUCCEEDED(hr) (!FAILED(hr)) /** \brief Estructura con datos relativos al estado del proceso.
*/
/** \brief Macro para generar nuevos códigos de error. typedef struct node_data_
En \a typ el tipo de error reportado (cero para errores de sistema). {
En \a cod el código numérico correspondiente a ese error. */ int num;
#define MAKE_ERROR_CODE(typ, cod) ((HRESULT)(0x8000 | ((typ & 0x7f) << 8) | (cod & } node_data;
0xff)))
/** \brief Elemento de la lista de procesos.
/** \brief Macro para generar nuevos códigos de éxito en la ejecuación de la función. */
En \a typ el tipo de éxito reportado (cero para códigos de sistema). typedef struct node_
En \a cod el código numérico correspondiente a ese error. */ {
#define MAKE_SUCCESS_CODE(typ, cod) ((HRESULT)(((typ & 0x7f) << 8) | (cod & 0xff))) node_data data; ///< Datos para almacenar el estado del proceso.
state_t state; ///< Estado de activación del hilo.
/// La función se ha ejecutado correctamente. priority_t priority; ///< Prioridad del hilo.
#define S_OK 0 struct node_ *pPrev, *pNext;/**< Punteros anterior y posterior a hilos
de igual prioridad */
/// OK, el resultado es verdadero. } node;
#define S_TRUE MAKE_SUCCESS_CODE(0,1)
/// OK, el resultado es falso. /** \brief Almacén de nodos para todas las listas.
#define S_FALSE MAKE_SUCCESS_CODE(0,2) * Contenedor de todos los nodos a usar, y punteros a sus cabeceras.
. . . . . . . . .
*/
/// OK, la función se ejecutará con retraso. typedef struct list_static_nodes_
#define S_DELAYED MAKE_SUCCESS_CODE(0,3) {
short numFree; ///< Número de nodos libres.
node aNodes[NUM_NODES]; ///< Array de nodos. Para no tener que usar memoria
/// Error genérico. dinámica.
#define E_FAIL -1 node* aHeads[NP_LAST]; ///< Punteros a las cabezas de las listas.
} list_static_nodes;
/// Función no implementada.
#define E_NOTIMPL MAKE_ERROR_CODE(0,1) /** \brief Muestra información sobre los datos vinculados al nodo.
* \param pData [in] Puntero a los datos a mostrar.
/// Sin memoria para efectuar la operación. * \return Valor \c HRETURN de retorno. Puede ser uno de los siguientes valores:
#define E_OUTOFMEM MAKE_ERROR_CODE(0,2) * - \c S_OK.- La ejecución ha sido correcta.
* - \c E_INVALIDARG.- El puntero de entrada contiene un valor no válido.
/// Argumento inválido. */
#define E_INVALIDARG MAKE_ERROR_CODE(0,3) HRESULT ShowNodeData(const node_data* pData)
{
/// Se ha sobrepasado una temporización. if(pData == NULL)
#define E_OUTOFTIME MAKE_ERROR_CODE(0,4) return E_INVALIDARG;
/// Error indeterminado. printf("%d", pData->num);
#define E_UNKNOWN MAKE_ERROR_CODE(0,5)
return S_OK;
/// Se ha especificado un valor fuera de rango. }
#define E_OUTOFRANGE MAKE_ERROR_CODE(0,6)
/** Muestra el contenido de todas las listas a las que referencia \a pList.
/// El contenedor está vacío. * \param pList [in] Puntero al array de listas.
#define E_EMPTY MAKE_ERROR_CODE(0,7) * \return Valor \c HRETURN de retorno. Puede ser uno de los siguientes valores:
* - \c S_OK.- La ejecución ha sido correcta.
/// El contenedor está lleno. * - \c E_INVALIDARG.- El puntero de entrada contiene un valor no válido.
#define E_FULL MAKE_ERROR_CODE(0,8) */
HRESULT ShowListContents(const list_static_nodes* pList)
#ifndef NULL {
/// Puntero nulo. if(pList == NULL)
#define NULL ((void*) 0) return E_INVALIDARG;
#endif
printf("Número de potenciales nodos: %d\n", pList->numFree);
/** \brief Obtiene la cadena de caracteres correspondiente a
* un código resultado HRESULT. for(char cont=NP_LAST-1; cont>0; --cont)
* \note Esta función sólo se debería usar en depuración de un programa empotrado. {
* \param hr Código de error a transformar. node* pNode, *pHead;
* \return Cadena de texto explicativa del error.
*/ pHead = pList->aHeads[cont];
const char* HResultToString(HRESULT hr)
{ if(pHead == NULL)
const char* szRes; {
printf("Sin nodos para la lista %d.\n", cont);
switch(hr) continue;
{ }
case S_OK: szRes = "S_OK. "; break;
case S_TRUE: szRes = "S_TRUE: OK, el resultado es verdadero. "; break; printf("Nodos de la lista %d: \n\tContenidos:", cont);
case S_FALSE: szRes = "S_FALSE: OK, el resultado es falso. "; break;
case S_DELAYED: szRes = "S_DELAYED: OK, la función se ejecutará con retraso. pNode = pHead;
"; break;
case E_FAIL: szRes = "E_FAIL: Error genérico. "; break; do
case E_NOTIMPL: szRes = "E_NOTIMPL: Función no implementada. "; break; {
case E_OUTOFMEM: szRes = "E_OUTOFMEM: Sin memoria para efectuar la printf("[");
operación. "; break; ShowNodeData(&pNode->data);
case E_INVALIDARG: szRes = "E_INVALIDARG: Argumento inválido. "; break; printf("] ");
case E_OUTOFTIME: szRes = "E_OUTOFTIME: Se ha sobrepasado una temporización.
"; break; pNode = pNode->pNext;
case E_UNKNOWN: szRes = "E_UNKNOWN: Error indeterminado. "; break; } while(pNode != pHead);
case E_OUTOFRANGE: szRes = "E_OUTOFRANGE: Se ha especificado un valor fuera
de rango. "; break; printf("\n");
case E_EMPTY: szRes = "E_EMPTY: El contenedor está vacío. "; break; }
case E_FULL: szRes = "E_FULL: El contenedor está lleno. "; break;
default: szRes = "ERROR: Código no reconocido. "; printf("\n");
}
return S_OK;
return szRes; }
}
/** Inicia la estructura apuntada por \a pList del tipo \b list_static_nodes
/// Número máximo de hilos permitido * para poder ser utilizada por otras funciones.
#define NUM_NODES 20 * \param pList [in, out] Puntero al array de listas a ser iniciadas.
* \return Valor \c HRETURN de retorno. Puede ser uno de los siguientes valores:
/// Estado de un hilo. * - \c S_OK.- La ejecución ha sido correcta.
enum node_state * - \c E_INVALIDARG.- El puntero de entrada contiene un valor no válido.
{ */
NS_NONE = 0, ///< Sin ejecución. HRESULT InitStaticNodesList(list_static_nodes* pList)
NS_READY, ///< Preparado para ejecución. {
Laboratorio de Informática Industrial II Departamento de Automática.
..
..
node *pNode;
.. */
HRESULT AddNode(list_static_nodes* pList,
if(pList == NULL)
return E_INVALIDARG;
.. priority_t priority,
const node_data* pData,
pNode = &pList->aNodes[0];
..
memset(pList, 0, sizeof(*pList)); {
HRESULT hr;
node *pNode;
node** ppNode = NULL)
pList->aHeads[NP_NONE] = pNode;
if(ppNode)
for(int i = 1; i < NUM_NODES; i++) *ppNode = NULL;
{
node *pCurNode = &pList->aNodes[i]; if(pData == NULL || pList == NULL)
return E_INVALIDARG;
pCurNode->pPrev = pNode;
pNode->pNext = pCurNode; if(pList->numFree == NULL)
return E_OUTOFMEM;
pNode = pCurNode;
} if(priority == NP_NONE || priority >= NP_LAST)
return E_OUTOFRANGE;
pNode->pNext = &pList->aNodes[0];
pList->aHeads[NP_NONE]->pPrev = pNode; pNode = pList->aHeads[NP_NONE];
/** Crea un nuevo nodo y lo añade a la lista cuya prioridad sea priority
* \param pList [in, out] Listas de nodos.
* \param priority [in] Prioridad del nuevo nodo.
* \param pData [in] Datos asociados con el nuevo hilo
* \param ppNode [out, optional] Dirección de un puntero a nodo que será iniciado
* con la dirección del nuevo nodo.
* \return Valor \c HRETURN de retorno. Puede ser uno de los siguientes:
* - \c S_OK.- La ejecución ha sido correcta.
* - \c E_OUTOFRANGE.- La prioridad del nodo no es correcta.
* - \c E_INVALIDARG.- Alguno de los argumentos contiene valores inválidos.
* - \c E_OUTOFMEM.- No quedan nodos libres para añadir uno más.