T168_111\system\NutOS:第10~17

NutFs.h    。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

#ifndef NUTFS_H

/******************************************************************************
 *                                                                            *
 *                         M O D U L E   D E F I N E                          *
 *                                                                            *
 ******************************************************************************/

#define NUTFS_H

/******************************************************************************
 *                                                                            *
 *        C O M P I L E R   D E F I N E D   I N C L U D E   F I L E S         *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *            U S E R   D E F I N E D   I N C L U D E   F I L E S             *
 *                                                                            *
 ******************************************************************************/

#include "NutFile.h"

#ifdef __cplusplus
extern "C" {            /* Assume C declarations for C++ */
#endif    /* __cplusplus */

/******************************************************************************
 *                                                                            *
 *                        G L O B A L   D E F I N E S                         *
 *                                                                            *
 ******************************************************************************/

/*!
 * \brief Obtain information about a specified file entry.
 */
#define FS_STATUS       0x1101

/*!
 * \brief Create a new directory entry.
 */
#define FS_DIR_CREATE   0x1111

/*!
 * \brief Remove a previously created directory entry.
 */
#define FS_DIR_REMOVE   0x1112

/*!
 * \brief Open a directory stream.
 */
#define FS_DIR_OPEN     0x1113

/*!
 * \brief Close a directory stream.
 */
#define FS_DIR_CLOSE    0x1114

/*!
 * \brief Read the next directory entry.
 */
#define FS_DIR_READ     0x1115

/*!
 * \brief Obtain information about an opened file.
 */
#define FS_FILE_STATUS  0x1121

/*!
 * \brief Remove a previously created file.
 */
#define FS_FILE_DELETE  0x1122

/*!
 * \brief Set a file pointer position.
 */
#define FS_FILE_SEEK    0x1123

#define FS_VOL_MOUNT    0x1130
#define FS_VOL_UNMOUNT  0x1131
#define FS_RENAME       0x1132
#define NUTFS_UNLINK    0x1133
#define NUTFS_MKDIR     0x1134
#define NUTFS_RMDIR     0x1135

/******************************************************************************
 *                                                                            *
 *                 S T R U C T U R E   D E F I N I T I O N S                  *
 *                                                                            *
 ******************************************************************************/

/*!
 * \brief General structure for two arguments.
 *
 * Used to pass two arguments to an I/O control function.
 */
typedef struct {
    void *arg1;
    void *arg2;
} IOCTL_ARG2;

/*!
 * \brief General structure for three arguments.
 *
 * Used to pass three arguments to an I/O control function.
 */
typedef struct {
    void *arg1;
    void *arg2;
    void *arg3;
} IOCTL_ARG3;

typedef struct _FSCP_VOL_MOUNT {
    /*! \brief Block device mount. */
    NUTFILE *fscp_bmnt;
    /*! \brief Partition type. */
    u_char fscp_part_type;
} FSCP_VOL_MOUNT;

typedef struct _FSCP_RENAME {
    CONST char *par_old;
    CONST char *par_new;
} FSCP_RENAME;

//typedef struct _FSCP_STATUS {
//    CONST char *par_path;
//    struct stat *par_stp;
//} FSCP_STATUS;

/******************************************************************************
 *                                                                            *
 *    G L O B A L   V A R I A B L E S   -   N O   I N I T I A L I Z E R S     *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *       G L O B A L   V A R I A B L E S   -   I N I T I A L I Z E R S        *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *                   F U N C T I O N   P R O T O T Y P E S                    *
 *                                                                            *
 ******************************************************************************/

#ifdef __cplusplus
}                       /* End of extern "C" { */
#endif    /* __cplusplus */

#endif

NutHeap.c               。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

/******************************************************************************
 *                                                                            *
 *                         M O D U L E   D E F I N E                          *
 *                                                                            *
 ******************************************************************************/

#define NUTHEAP_C

/******************************************************************************
 *                                                                            *
 *        C O M P I L E R   D E F I N E D   I N C L U D E   F I L E S         *
 *                                                                            *
 ******************************************************************************/

#include <stdio.h>
#include <string.h>

/******************************************************************************
 *                                                                            *
 *            U S E R   D E F I N E D   I N C L U D E   F I L E S             *
 *                                                                            *
 ******************************************************************************/

#include "Common.h"
#include "XCore.h"
#include "NutHeap.h"

#if defined(NUTOS)

/******************************************************************************
 *                                                                            *
 *                         L O C A L   D E F I N E S                          *
 *                                                                            *
 ******************************************************************************/

#ifndef NUTMEM_ALIGNMENT
#define    NUTMEM_ALIGNMENT        sizeof(int)
#endif

/*!
 * \brief Return the next lower aligned value.
 */
#define    NUTMEM_BOTTOM_ALIGN(s)  ((s) & ~(NUTMEM_ALIGNMENT - 1))

/*!
 * \brief Return the next higher aligned value.
 */
#define    NUTMEM_TOP_ALIGN(s)     NUTMEM_BOTTOM_ALIGN((s + (NUTMEM_ALIGNMENT - 1)))

/*
 * Set optional memory guard bytes.
 */
#ifdef NUTMEM_GUARD
#ifndef NUTMEM_GUARD_PATTERN
#define NUTMEM_GUARD_PATTERN   ((int)(0xDEADBEEF))
#endif
#define NUTMEM_GUARD_BYTES     sizeof(NUTMEM_GUARD_PATTERN)
#else /* NUTMEM_GUARD */
#define NUTMEM_GUARD_BYTES     0
#endif /* NUTMEM_GUARD */

/*! \brief Number of bytes used for management information. */
#define NUT_HEAP_OVERHEAD   (sizeof(HEAPNODE) - sizeof(HEAPNODE *))

/*! \brief Minimum size of a node. */
#ifndef NUTMEM_HEAPNODE_MIN
#define NUTMEM_HEAPNODE_MIN (sizeof(HEAPNODE) + (2 * NUTMEM_GUARD_BYTES))
#endif

/******************************************************************************
 *                                                                            *
 *                        L O C A L   T Y P E D E F S                         *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *             L O C A L   F U N C T I O N   P R O T O T Y P E S              *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *    L O C A L   I N I T I A L I Z E D   D A T A   D E F I N I T I O N S     *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *    L O C A L   U N I T I A L I Z E D   D A T A   D E F I N I T I O N S     *
 *                                                                            *
 ******************************************************************************/


/*
 * Prepare the user region.
 *
 * Returns a pointer to the memory block's user region, after optionally
 * having added guard patterns at both ends.
 */
static INLINE void *PrepareUserArea(HEAPNODE * node)
{
    int *tp = (int *) (uptr_t) &node->hn_next;
#ifdef NUTMEM_GUARD
    size_t off = (node->hn_size - NUT_HEAP_OVERHEAD) / sizeof(int) - 2;

    *tp++ = NUTMEM_GUARD_PATTERN;
    *(tp + off) = NUTMEM_GUARD_PATTERN;
#endif
    return tp;
}

/*
 * Validate the user region.
 *
 * If we have guarded user regions, then this routine will do a sanity
 * check. If the guards had been overridden, then -1 is returned.
 * However, if running in debug mode, then NUTPANIC is called instead.
 *
 * If the guards are still OK or if guard protection is not available,
 * then zero is returned.
 */
static INLINE int ValidateUserArea(HEAPNODE * node)
{
#ifdef NUTMEM_GUARD
    size_t off = (node->hn_size - NUT_HEAP_OVERHEAD) / sizeof(int) - 1;
    int *tp = (int *) (uptr_t) &node->hn_next;

    if (*tp != NUTMEM_GUARD_PATTERN || *(tp + off) != NUTMEM_GUARD_PATTERN) {
        return -1;
    }
#endif
    return 0;
}

/*!
 * \brief Allocate a block from heap memory.
 *
 * This functions allocates a memory block of the specified size and 
 * returns a pointer to that block.
 *
 * The actual size of the allocated block is larger than the requested 
 * size because of space required for maintenance information. This 
 * additional information is invisible to the application.
 *
 * The routine looks for the smallest block that will meet the required 
 * size and releases it to the caller. If the block being requested is 
 * usefully smaller than the smallest free block then the block from 
 * which the request is being met is split in two. The unused portion is 
 * put back into the free-list.
 *
 * The contents of the allocated block is unspecified. To allocate a 
 * block with all bytes set to zero use NutHeapAllocClear().
 *
 * \param root Points to the linked list of free nodes.
 * \param size Size of the requested memory block.
 *
 * \return Pointer to the allocated memory block if the function is 
 *         successful or NULL if no free block of the requested size
 *         is available.
 */
void *NutHeapRootAlloc(HEAPNODE ** root, size_t size)
{
    HEAPNODE *node;
    HEAPNODE **npp;
    HEAPNODE *fit = NULL;
    HEAPNODE **fpp = NULL;
    size_t need;

    /* Determine the minimum size. Add optional guard and alignment bytes.
       ** Make sure that a HEAPNODE structure fits. */
    need = size + NUT_HEAP_OVERHEAD + 2 * NUTMEM_GUARD_BYTES;
    if (need < sizeof(HEAPNODE)) {
        need = sizeof(HEAPNODE);
    }
    need = NUTMEM_TOP_ALIGN(need);

    /*
     * Walk through the linked list of free nodes and find the best fit.
     */
    node = *root;
    npp = root;
    while (node) {
        /* Found a note that fits? */
        if (node->hn_size >= need) {
            /* Is it the first one we found or was the previous 
               ** one larger? */
            if (fit == NULL || fit->hn_size > node->hn_size) {
                /* This is the best fit so far. */
                fit = node;
                fpp = npp;
                /* Is this an exact match? */
                if (node->hn_size == need) {
                    /* Exact match found. Stop searching. */
                    break;
                }
            }
        }
        npp = &node->hn_next;
        node = node->hn_next;
    }

    if (fit) {
        /* Is remaining space of the node we found large enough for 
           another node? Honor the specified threshold. */
        if (fit->hn_size - need >= NUTMEM_HEAPNODE_MIN) {
            /* Split the node. */
            node = (HEAPNODE *) ((uptr_t) fit + need);
            node->hn_size = fit->hn_size - need;
            node->hn_next = fit->hn_next;
            fit->hn_size = need;
            *fpp = node;
        } else {
            /* Use the full node. */
            *fpp = fit->hn_next;
        }
        fit = (HEAPNODE *) PrepareUserArea(fit);
    }
    return fit;
}

/*!
 * \brief Allocate an initialized block from heap memory.
 *
 * This functions allocates a memory block of the specified
 * size with all bytes initialized to zero and returns a
 * pointer to that block.
 *
 * \param root Points to the linked list of free nodes.
 * \param size Size of the requested memory block.
 *
 * \return Pointer to the allocated memory block if the
 *         function is successful or NULL if the requested
 *         amount of memory is not available.
 */
void *NutHeapRootAllocClear(HEAPNODE ** root, size_t size)
{
    void *ptr;

    if ((ptr = NutHeapRootAlloc(root, size)) != 0)
        memset(ptr, 0, size);

    return ptr;
}

/*!
 * \brief Return a block to heap memory.
 *
 * An application calls this function, when a previously allocated 
 * memory block is no longer needed.
 *
 * The heap manager checks, if the released block adjoins any other 
 * free regions. If it does, then the adjacent free regions are joined 
 * together to form one larger region.
 *
 * \param root  Points to the linked list of free nodes.
 * \param block Points to a memory block previously allocated.
 *
 * \return 0 on success, -1 if the caller tried to free a block which 
 *         had been previously released, -2 if the block had been
 *         corrupted. Furthermore, -3 is returned if block is a NULL
 *         pointer, but using this may change as C99 allows this.
 */
int NutHeapRootFree(HEAPNODE ** root, void *block)
{
    HEAPNODE *node;
    HEAPNODE **npp;
    HEAPNODE *fnode;

    /* IMHO, this should be removed. It adds additional code, which is
       useless for most applications. Those, who are interested, can
       easily do their own check. C99 declares this as a NUL op. */
    if (block == NULL) {
        return -3;
    }

    /* Revive our node pointer. */
    fnode = (HEAPNODE *) ((uptr_t) block - (NUT_HEAP_OVERHEAD + NUTMEM_GUARD_BYTES));

    if (ValidateUserArea(fnode)) {
        return -2;
    }

    /*
     * Walk through the linked list of free nodes and try
     * to link us in.
     */
    node = *root;
    npp = root;
    while (node) {
        /* If this node is directly in front of ours, merge it. */
        if ((uptr_t) node + node->hn_size == (uptr_t) fnode) {
            node->hn_size += fnode->hn_size;

            /*
             * If another free node is directly following us, merge it.
             */
            if (((uptr_t) node + node->hn_size) == (uptr_t) node->hn_next) {
                node->hn_size += node->hn_next->hn_size;
                node->hn_next = node->hn_next->hn_next;
            }
            break;
        }

        /*
         * If we walked past our address, link us to the list.
         */
        if ((uptr_t) node > (uptr_t) fnode) {
            *npp = fnode;

            /*
             * If a free node is following us, merge it.
             */
            if (((uptr_t) fnode + fnode->hn_size) == (uptr_t) node) {
                fnode->hn_size += node->hn_size;
                fnode->hn_next = node->hn_next;
            } else
                fnode->hn_next = node;
            break;
        }

        /*
         * If we are within a free node, somebody tried
         * to free a block twice.
         */
        if (((uptr_t) node + node->hn_size) > (uptr_t) fnode) {
            return -1;
        }

        npp = &node->hn_next;
        node = node->hn_next;
    }

    /*
     * If no link was found, put us at the end of the list
     */
    if (node == NULL) {
        fnode->hn_next = node;
        *npp = fnode;
    }
    return 0;
}

/*!
 * \brief Add a new memory region to the heap.
 *
 * This function can be called more than once to manage non-continous
 * memory regions. It is automatically called by Nut/OS during 
 * initialization.
 *
 * \param addr Start address of the memory region.
 * \param size Number of bytes of the memory region.
 */
void NutHeapRootAdd(HEAPNODE ** root, void *addr, size_t size)
{
    HEAPNODE *node = (HEAPNODE *) NUTMEM_TOP_ALIGN((uptr_t) addr);

    node->hn_size = NUTMEM_BOTTOM_ALIGN(size - ((uptr_t) node - (uptr_t) addr));
    NutHeapRootFree(root, PrepareUserArea(node));
}

/*!
 * \brief Return the total number of bytes available.
 *
 * \return Number of bytes.
 */
size_t NutHeapRootAvailable(HEAPNODE ** root)
{
    size_t rc = 0;
    HEAPNODE *node;

    /* Collect all free nodes. */
    for (node = *root; node; node = node->hn_next) {
        /* Reduce the size of each node by the required overhead. */
        rc += node->hn_size - NUT_HEAP_OVERHEAD;
    }
    return rc;
}

/*!
 * \brief Return the size of the largest block available.
 *
 * \return Number of bytes.
 */
size_t NutHeapRootRegionAvailable(HEAPNODE ** root)
{
    size_t rc = 0;
    HEAPNODE *node;

    /* Collect all free nodes. */
    for (node = *root; node; node = node->hn_next) {
        if (rc < node->hn_size) {
            rc = node->hn_size;
        }
    }
    /* Reduce the size by the required overhead. */
    return rc - NUT_HEAP_OVERHEAD;
}

/**
 * \brief Change the size of an allocated memory block.
 * 
 * If more memory is requested than available at that block the data
 * is copied to a new, bigger block.
 * 
 * \param block Points to a previously allocated memory block. If NULL,
 *              then this call is equivalent to NutHeapRootAlloc().
 * \param size  The requested new size. If 0, then this call is
 *              equivalent to NutHeapRootFree().
 * 
 * \return A pointer to the memory block on success or NULL on failures.
 */
void *NutHeapRootRealloc(HEAPNODE ** root, void *block, size_t size)
{
    HEAPNODE *node;
    HEAPNODE **npp;
    HEAPNODE *fnode;
    void *newmem;

    if (block == NULL) {
        return NutHeapRootAlloc(root, size);
    }
    if (size == 0) {
        if (NutHeapRootFree(root, block)) {
            return NULL;
        }
        return block;
    }
    fnode = (HEAPNODE *) ((uptr_t) block - (NUT_HEAP_OVERHEAD + NUTMEM_GUARD_BYTES));
    if (ValidateUserArea(fnode)) {
        return NULL;
    }

    /* Determine the minimum size. Add optional guard and alignment bytes.
       Make sure that a HEAPNODE structure fits. */
    size += NUT_HEAP_OVERHEAD + NUTMEM_GUARD_BYTES * 2;
    if (size < sizeof(HEAPNODE)) {
        size = sizeof(HEAPNODE);
    }
    size = NUTMEM_TOP_ALIGN(size);

    /*
     * Expansion.
     */
    if (size > fnode->hn_size) {
        size_t size_miss = size - fnode->hn_size;

        /* Find the free node following next. */
        node = *root;
        npp = root;
        while (node && node < fnode) {
            npp = &node->hn_next;
            node = node->hn_next;
        }

        /* If we found a node and if this node is large enough and 
           if it directly follows without a gap, then use it. */
        if (node && node->hn_size >= size_miss &&       /* */
            (uptr_t) fnode + fnode->hn_size == (uptr_t) node) {
            /* Check if the following node is large enough to be split. */
            if (node->hn_size - size_miss >= NUTMEM_HEAPNODE_MIN) {
                /* Adjust the allocated size. */
                fnode->hn_size += size_miss;
                /* Insert the remaining part into the free list. */
                *npp = (HEAPNODE *) ((uptr_t) node + size_miss);
                /* Due to possible overlapping it is important to set
                   the pointer first, then the size. */
                (*npp)->hn_next = node->hn_next;
                (*npp)->hn_size = node->hn_size - size_miss;
                PrepareUserArea(fnode);
            } else {
                /* Adjust the allocated size. */
                fnode->hn_size += node->hn_size;
                PrepareUserArea(fnode);
                /* Remove the merged node from the free list. */
                *npp = node->hn_next;
            }
            /* Return the original pointer. */
            return block;
        }

        /* Relocate if no sufficiently large block follows. */
        newmem = NutHeapRootAlloc(root, size);
        if (newmem) {
            memcpy(newmem, block, 
                fnode->hn_size - NUT_HEAP_OVERHEAD - 2 * NUTMEM_GUARD_BYTES);
            NutHeapRootFree(root, block);
        }
        return newmem;
    }

    /*
     * Reduction.
     */
    if (size < fnode->hn_size - NUTMEM_HEAPNODE_MIN) {
        /* Release the remaining part to the free list. */
        node = (HEAPNODE *) ((uptr_t) fnode + size);
        node->hn_size = fnode->hn_size - size;
        NutHeapRootFree(root, PrepareUserArea(node));
        /* Adjust the allocated size. */
        fnode->hn_size = size;
        PrepareUserArea(fnode);
    }
    return block;
}

/*!
 * \brief Dump heap memory to a given stream.
 */
void NutHeapDump(void * stream)
{
    HEAPNODE *node;

    for (node = heapFreeList; node; node = node->hn_next) {
        fprintf(stream, "%p(%d)\n", node, (int) node->hn_size);
    }
}

#endif

NutHeap.h          。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

#ifndef NUTHEAP_H

/******************************************************************************
 *                                                                            *
 *                         M O D U L E   D E F I N E                          *
 *                                                                            *
 ******************************************************************************/

#define NUTHEAP_H

/******************************************************************************
 *                                                                            *
 *        C O M P I L E R   D E F I N E D   I N C L U D E   F I L E S         *
 *                                                                            *
 ******************************************************************************/

#include <stdio.h>

/******************************************************************************
 *                                                                            *
 *            U S E R   D E F I N E D   I N C L U D E   F I L E S             *
 *                                                                            *
 ******************************************************************************/

#ifdef __cplusplus
extern "C" {            /* Assume C declarations for C++ */
#endif    /* __cplusplus */

/******************************************************************************
 *                                                                            *
 *                        G L O B A L   D E F I N E S                         *
 *                                                                            *
 ******************************************************************************/

#define NutHeapAdd(a, s)                NutHeapRootAdd(&heapFreeList, a, s)
#define NutHeapAvailable()              NutHeapRootAvailable(&heapFreeList)
#define NutHeapRegionAvailable()        NutHeapRootRegionAvailable(&heapFreeList)
#define NutHeapAlloc(s)                 NutHeapRootAlloc(&heapFreeList, s)
#define NutHeapAllocClear(s)            NutHeapRootAllocClear(&heapFreeList, s)
#define NutHeapFree(p)                  NutHeapRootFree(&heapFreeList, p)
#define NutHeapRealloc(p, s)            NutHeapRootRealloc(&heapFreeList, p, s)

/* Thread stacks resides in normal heap. */
#define NutStackAlloc(s)                NutHeapAlloc(s)
#define NutStackFree(p)                 NutHeapFree(p)

/******************************************************************************
 *                                                                            *
 *                 S T R U C T U R E   D E F I N I T I O N S                  *
 *                                                                            *
 ******************************************************************************/

/*!
 * \struct _HEAPNODE heap.h sys/heap.h
 * \brief Heap memory node information structure.
 */
typedef struct _HEAPNODE HEAPNODE;

/*!
 * \typedef HEAPNODE
 * \brief Heap memory node type.
 */
struct _HEAPNODE {
    size_t hn_size;     /*!< \brief Size of this node. */
    HEAPNODE *hn_next;  /*!< \brief Link to next free node. */
};

/******************************************************************************
 *                                                                            *
 *    G L O B A L   V A R I A B L E S   -   N O   I N I T I A L I Z E R S     *
 *                                                                            *
 ******************************************************************************/

#ifdef NUTHEAP_C
#define EXTERN
#else
#define EXTERN extern
#endif

/*!
 * \brief List of free nodes in normal memory.
 */
EXTERN HEAPNODE *heapFreeList;

/******************************************************************************
 *                                                                            *
 *       G L O B A L   V A R I A B L E S   -   I N I T I A L I Z E R S        *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *                   F U N C T I O N   P R O T O T Y P E S                    *
 *                                                                            *
 ******************************************************************************/

#if defined(NUTOS)
void NutHeapRootAdd(HEAPNODE** root, void *addr, size_t size);
size_t NutHeapRootAvailable(HEAPNODE** root);
size_t NutHeapRootRegionAvailable(HEAPNODE** root);
void *NutHeapRootAlloc(HEAPNODE** root, size_t size);
void *NutHeapRootAllocClear(HEAPNODE** root, size_t size);
int NutHeapRootFree(HEAPNODE** root, void *block);
void *NutHeapRootRealloc(HEAPNODE** root, void * block, size_t size);
void NutHeapDump(void * stream);

#else
#define NutHeapRootAdd(root, addr, size)
#define NutHeapRootAvailable(root)              (0)
#define NutHeapRootRegionAvailable(root)        (0)
#define NutHeapRootAlloc(root, size)            (0)
#define NutHeapRootAllocClear(root, size)       (0)
#define NutHeapRootFree(root, block)            (0)
#define NutHeapRootRealloc(root, block, size)   (0)
#define NutHeapDump(stream)

#endif

#undef EXTERN

#ifdef __cplusplus
}                       /* End of extern "C" { */
#endif    /* __cplusplus */

#endif

NutOS.h               。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

#ifndef NUTOS_H

/******************************************************************************
 *                                                                            *
 *                         M O D U L E   D E F I N E                          *
 *                                                                            *
 ******************************************************************************/

#define NUTOS_H

/******************************************************************************
 *                                                                            *
 *        C O M P I L E R   D E F I N E D   I N C L U D E   F I L E S         *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *            U S E R   D E F I N E D   I N C L U D E   F I L E S             *
 *                                                                            *
 ******************************************************************************/

#include "NutHeap.h"
#include "NutConfos.h"
#include "NutDevice.h"
#include "NutTimer.h"
#include "NutEvent.h"
#include "NutThread.h"
#include "NutFs.h"

#include "NutDebug.h"

#ifdef __cplusplus
extern "C" {            /* Assume C declarations for C++ */
#endif    /* __cplusplus */

/******************************************************************************
 *                                                                            *
 *                        G L O B A L   D E F I N E S                         *
 *                                                                            *
 ******************************************************************************/

/*!
 * Number of bytes of the stack space allocated for the new thread.
 */

#define NUT_HEAP_SIZE                    (1024 * 1024/*512*/)
#define NUT_THREAD_IDLE_STACK            (1024 * 1)
#define NUT_THREAD_MAIN_STACK            (1024 * 64)
#define NUT_THREAD_TASK_STACK            (1024 * 2)
#define NUT_THREAD_HOST_STACK            (1024 * 4)
#define NUT_THREAD_ETHERNET_STACK        (1024 * 2)
#define NUT_THREAD_NICRX_STACK            (1024 * 2)
#define NUT_THREAD_DHCP_STACK            (1024 * 1)
#define NUT_THREAD_TCPSM_STACK            (1024 * 1)
#define NUT_THREAD_SNTP_STACK            (1024 * 1)
#define NUT_THREAD_SNMP_STACK            (1024 * 2)
#define NUT_THREAD_UTILITY_STACK        (1024 * 2)
#define NUT_THREAD_MAIL_STACK            (1024 * 4)
#define NUT_THREAD_FTP_STACK            (1024 * 2)
#define NUT_THREAD_TELNET_STACK            (1024 * 2)
#define NUT_THREAD_HTTP_STACK            (1024 * 4)
#define NUT_THREAD_LPR_STACK            (1024 * 2)
#define NUT_THREAD_RAW_STACK            (1024 * 2)
#define NUT_THREAD_CARRIAGE_HOME_STACK  (1024 * 1)

/*!
 * The priority of newly created threads is set to 64,
 * but may be changed when the thread starts running.
 *
 * 255 to kill the thread. Zero specifies the highest priority.
 * The idle thread is running at level 254 (lowest priority).
 * Application threads should use levels from 32 to 253.
 */

#define NUT_THREAD_KILL_PRIORITY        255
#define NUT_THREAD_IDLE_PRIORITY        254
#define NUT_THREAD_MAIN_PRIORITY        200
#define NUT_THREAD_TASK_PRIORITY        128
#define NUT_THREAD_HOST_PRIORITY        48
#define NUT_THREAD_ETHERNET_PRIORITY
#define NUT_THREAD_NICRX_PRIORITY        9
#define NUT_THREAD_DHCP_PRIORITY
#define NUT_THREAD_TCPSM_PRIORITY        32
#define NUT_THREAD_SNTP_PRIORITY        63
#define NUT_THREAD_SNMP_PRIORITY
#define NUT_THREAD_UTILITY_PRIORITY
#define NUT_THREAD_MAIL_PRIORITY        96
#define NUT_THREAD_SERVICE_PRIORITY

/******************************************************************************
 *                                                                            *
 *                 S T R U C T U R E   D E F I N I T I O N S                  *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *    G L O B A L   V A R I A B L E S   -   N O   I N I T I A L I Z E R S     *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *       G L O B A L   V A R I A B L E S   -   I N I T I A L I Z E R S        *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *                   F U N C T I O N   P R O T O T Y P E S                    *
 *                                                                            *
 ******************************************************************************/

#ifdef __cplusplus
}                       /* End of extern "C" { */
#endif    /* __cplusplus */

#endif    

NutThread.c               。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

/******************************************************************************
 *                                                                            *
 *                         M O D U L E   D E F I N E                          *
 *                                                                            *
 ******************************************************************************/

#define NUTTHREAD_C

/******************************************************************************
 *                                                                            *
 *        C O M P I L E R   D E F I N E D   I N C L U D E   F I L E S         *
 *                                                                            *
 ******************************************************************************/

#include <string.h>

/******************************************************************************
 *                                                                            *
 *            U S E R   D E F I N E D   I N C L U D E   F I L E S             *
 *                                                                            *
 ******************************************************************************/

#include "Common.h"
#include "XCore.h"
#include "NutHeap.h"
#include "NutTimer.h"
#include "NutEvent.h"
#include "NutThread.h"
#include "XComm.h"
#ifdef NUTDEBUG
#include "NutDebug.h"
#endif

#if defined(NUTOS)

/******************************************************************************
 *                                                                            *
 *                         L O C A L   D E F I N E S                          *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *                        L O C A L   T Y P E D E F S                         *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *             L O C A L   F U N C T I O N   P R O T O T Y P E S              *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *    L O C A L   I N I T I A L I Z E D   D A T A   D E F I N I T I O N S     *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *    L O C A L   U N I T I A L I Z E D   D A T A   D E F I N I T I O N S     *
 *                                                                            *
 ******************************************************************************/

/*!
 * \brief Thread to be killed.
 *
 * Pointer to the NUTTHREADINFO structure of the latest
 * killed thread.
 */
NUTTHREADINFO * killedThread;


/*!
 * \brief Add a thread to a prioritiy ordered queue.
 *
 * Insert the thread into a specified queue behind
 * the last thread with lower or equal priority.
 *
 * \param td   Pointer to NUTTHREADINFO of the thread to be
 *             inserted in the queue.
 * \param tqpp Pointer to the root of the queue.
 */
void NutThreadAddPriQueue(NUTTHREADINFO * td, NUTTHREADINFO * volatile *tqpp)
{
    NUTTHREADINFO *tqp;

    td->td_queue = (NUTHANDLE) tqpp;
    td->td_qpec = 0;            // start with clean event count

    /*
     * Be most careful not to override an intermediate event from interrupt 
     * context, which may change a queue from empty to signaled state. Many 
     * thanks to Michael Jones, who detected and corrected this bug.
     */
    NutEnterCritical();
    tqp = *tqpp;

    if (tqp == SIGNALED) {
        tqp = 0;
        td->td_qpec++;            // transfer the signaled state 
    } else if (tqp) {
        NutExitCritical();        // there are other threads in queue
                        // so its save to leave critical.          
        while (tqp && tqp->td_priority <= td->td_priority) {
            tqpp = &tqp->td_qnxt;
            tqp = tqp->td_qnxt;
        }

        NutEnterCritical();        // back into critical
    }
    td->td_qnxt = tqp;

    *tqpp = td;
    if (td->td_qnxt && td->td_qnxt->td_qpec) {
    //    td->td_qpec += (u_int)td->td_qnxt->td_qpec;    // don't overwrite count
        u_int qpec = td->td_qnxt->td_qpec;
        td->td_qpec += qpec;    // don't overwrite count
        td->td_qnxt->td_qpec = 0;
    }
    NutExitCritical();
}

/*!
 * \brief Remove a thread from a specified queue.
 *
 * \note Depending on the given queue, CPU interrupts must have
 * been disabled before calling this function.
 *
 * \param td   Pointer to NUTTHREADINFO of the thread to be
 *             removed from the queue.
 * \param tqpp Pointer to the root of the queue.
 */
void NutThreadRemoveQueue(NUTTHREADINFO * td, NUTTHREADINFO * volatile *tqpp)
{
    NUTTHREADINFO *tqp;

    NutEnterCritical();
    tqp = *tqpp;
    NutExitCritical();

    if (tqp != SIGNALED) {
        while (tqp) {
            if (tqp == td) {
                NutEnterCritical();
                *tqpp = td->td_qnxt;
                if (td->td_qpec) {
                    if (td->td_qnxt) {
                        td->td_qnxt->td_qpec = td->td_qpec;
                    }
                    td->td_qpec = 0;
                }
                NutExitCritical();

                td->td_qnxt = 0;
                td->td_queue = 0;
                break;
            }
            tqpp = &tqp->td_qnxt;
            tqp = tqp->td_qnxt;
        }
    }
}

/*!
 * \brief Continue with the highest priority thread, which is ready to run.
 *
 * If the currently running thread lost its top position in the queue
 * of ready-to-run threads, then the context will be switched.
 *
 * \todo Removing a single thread from a wait queue only improves context
 *       switching, but may result in an event time-out for remaining 
 *       threads, although events had been posted already.
 */
void NutThreadResume(void)
{
    NUTTHREADINFO *td;
    NUTTHREADINFO **qhp;
    NUTTHREADINFO *tqp;
    u_int cnt;

    /*
     * Process events that have been posted from interrupt context.
     */
    td = nutThreadList;
    while (td) {
        NutEnterCritical();
        cnt = td->td_qpec;
        NutExitCritical();
        if (cnt) {
            /* In order to reduce context switching time, it is sufficient 
             * to remove the thread on top of the priority ordered list. */
            qhp = (NUTTHREADINFO **)(td->td_queue);
            NutEnterCritical();
            td->td_qpec--;
            tqp = *qhp;
            NutExitCritical();
            if (tqp != SIGNALED) {
                NutEventPostAsync((NUTHANDLE *)qhp);
            }
        }
        td = td->td_next;
    }

    /*
     * Process elapsed timers. Must be done after processing the
     * events from interupt routines.
     */
    NutTimerProcessElapsed();

    /* Check for context switch. */
    if (runningThread != runQueue) {
        if (runningThread->td_state == TDS_RUNNING) {
            runningThread->td_state = TDS_READY;
        }
        NutEnterCritical();
        NutThreadSwitch();
        NutExitCritical();
    }
}

/*!
 * \brief Resume a previously suspended thread.
 *
 * This routine is called by the system when a
 * sleep timer elapses.
 *
 * \note This routine is used as a timer callback
 *       for NutSleep implementation
 *       Applications typically do not call this
 *       function.
 *
 * \param timer Handle of the elapsed timer.
 * \param th    Handle of the thread to wake up.
 *
 * \todo Used by the timer module. Should be moved there, because not all
 *       applications will use of NutSleep().
 */
void NutThreadWake(NUTHANDLE timer, NUTHANDLE th)
{
    /* clear pointer on timer and waiting queue */
    ((NUTTHREADINFO *) th)->td_timer = 0;
    ((NUTTHREADINFO *) th)->td_state = TDS_READY;
    NutThreadAddPriQueue(th, (NUTTHREADINFO **) & runQueue);
}

/*!
 * \brief Give up the CPU.
 *
 * If another thread within the same or higher priority
 * is ready to run, then the current thread is stopped
 * and the other one is started.
 *
 */
void NutThreadYield(void)
{
    /*
     * Remove current thread from runQueue and reinsert it.
     * The idle thread is the last one in the queue and will
     * never be removed.
     */
    if (runningThread->td_qnxt) {
        NutThreadRemoveQueue(runningThread, (NUTTHREADINFO **) & runQueue);
        NutThreadAddPriQueue(runningThread, (NUTTHREADINFO **) & runQueue);
    }

    /* Continue with the highest priority thread, which is ready to run. */
    NutThreadResume();
}

/*!
 * \brief Set the current thread's priority.
 *
 * The priority of newly created threads is set to 64,
 * but may be changed when the thread starts running.
 *
 * Changing the priority level to 255 will kill the
 * calling thread.
 *
 * When another thread with a higher or equal priority
 * is ready to run, the current thread will be stopped
 * and control of the CPU is passed to the other thread.
 *
 * The function returns the old priority, which makes it
 * easy to temporarily switch to another priority and
 * later set back the old one.
 *
 * \param level New priority level or 255 to kill the thread. Zero
 *              specifies the highest priority. The idle thread is
 *              running at level 254 (lowest priority). Application 
 *              threads should use levels from 32 to 253.
 *
 * \return The old priority of this thread.
 *
 * \todo Using a specific priority level for killing a thread is actually
 *       not the best idea. NutThreadKill() can be used instead.
 */
u_char NutThreadSetPriority(u_char level)
{
    u_char last = runningThread->td_priority;

    /*
     * Remove the thread from the run queue and re-insert it with a new
     * priority, if this new priority level is below 255. A priotity of
     * 255 will kill the thread.
     */
    NutThreadRemoveQueue(runningThread, &runQueue);
    runningThread->td_priority = level;
    if (level < 255) {
        NutThreadAddPriQueue(runningThread, (NUTTHREADINFO **) & runQueue);
    } else {
        NutThreadKill();
    }

    /*
     * Are we still on top of the queue? If yes, then change our status
     * back to running, otherwise do a context switch.
     */
    if (runningThread == runQueue) {
        runningThread->td_state = TDS_RUNNING;
    } else {
        runningThread->td_state = TDS_READY;

        NutEnterCritical();
        NutThreadSwitch();
        NutExitCritical();
    }

    return last;
}

/*!
 * \brief End the current thread
 *
 * Terminates the current thread, in due course the memory associated
 * with the thread will be released back to the OS this is done by the
 * idle thread.
 *
 * \todo NutThreadKill() can be used instead of setting the priority level
 *       to 255.
 */
void NutThreadExit(void)
{
    NutThreadSetPriority(255);
}

/*!
 * \brief Free a thread that was previously killed and release memory
 *        back to the OS.
 *
 * Called when another thread is killed and by the idle thread.
 *
 * Applications generally do not call this function, however you could
 * call it to try to reclaim memory.
 */
void NutThreadDestroy(void)
{
    if (killedThread) {
        NutStackFree(killedThread->td_memory);
        killedThread = 0;
    }
}

/*!
 * \brief Kill the running thread.
 *
 * The thread is moved from the schedule que and
 *
 * Applications generally do not call this function.
 */
void NutThreadKill(void)
{
    NUTTHREADINFO *pCur = nutThreadList;
    NUTTHREADINFO **pp = (NUTTHREADINFO **) & nutThreadList;

    /* Free up any unfinished already killed threads. */
    NutThreadDestroy();

    /* Remove from the thread list. */
    while (pCur) {
        if (pCur == runningThread) {
            *pp = pCur->td_next;
            break;
        }

        pp = (NUTTHREADINFO **) & pCur->td_next;
        pCur = pCur->td_next;
    }

    /* Schedule for cleanup. */
    killedThread = runningThread;
}

/*!
 * \brief Query handle of a thread with a specific name.
 *
 * \param name Case sensitive symbolic name of the thread.
 *
 * \return Handle of the thread, if it exists. Otherwise NULL is returned.
 *
 * \todo Rarely used helper function. Should be placed in a seperate module.
 */
NUTHANDLE GetThreadByName(char * name)
{
    NUTTHREADINFO *tdp;

    if (name) {
        for (tdp = nutThreadList; tdp; tdp = tdp->td_next) {
            if (strcmp(tdp->td_name, name) == 0)
                return tdp;
        }
    } else {
        return runningThread;
    }
    return NULL;
}

#endif

NutThread.h              。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

#ifndef NUTTHREAD_H

/******************************************************************************
 *                                                                            *
 *                         M O D U L E   D E F I N E                          *
 *                                                                            *
 ******************************************************************************/

#define NUTTHREAD_H

/******************************************************************************
 *                                                                            *
 *        C O M P I L E R   D E F I N E D   I N C L U D E   F I L E S         *
 *                                                                            *
 ******************************************************************************/

#include <stdio.h>

/******************************************************************************
 *                                                                            *
 *            U S E R   D E F I N E D   I N C L U D E   F I L E S             *
 *                                                                            *
 ******************************************************************************/

#ifdef __cplusplus
extern "C" {            /* Assume C declarations for C++ */
#endif    /* __cplusplus */

/******************************************************************************
 *                                                                            *
 *                        G L O B A L   D E F I N E S                         *
 *                                                                            *
 ******************************************************************************/

#define DEADBEEF    0xDEADBEEF

/*!
 * \name Thread States
 */
#define TDS_TERM        0       /*!< Thread has exited. */
#define TDS_RUNNING     1       /*!< Thread is running. */
#define TDS_READY       2       /*!< Thread is ready to run. */
#define TDS_SLEEP       3       /*!< Thread is sleeping. */

#define SLEEP_MODE_NONE 0xff

/******************************************************************************
 *                                                                            *
 *                 S T R U C T U R E   D E F I N I T I O N S                  *
 *                                                                            *
 ******************************************************************************/

/*!
 * Thread information structure type.
 */
typedef struct _NUTTHREADINFO NUTTHREADINFO;

/*!
 * \struct _NUTTHREADINFO thread.h sys/thread.h
 * \brief Thread information structure.
 *
 * \todo Sort items while considering alignment.
 */

struct _NUTTHREADINFO {
    NUTTHREADINFO *td_next;      /*!< \brief Linked list of all threads. */
    NUTTHREADINFO *td_qnxt;      /*!< \brief Linked list of all queued thread. */
    volatile u_int td_qpec;      /*!< \brief Pending event counter. */
    char td_name[9];             /*!< \brief Name of this thread. */
    u_char td_state;             /*!< \brief Operating state. One of TDS_ */
    uptr_t td_sp;                /*!< \brief Stack pointer. */
    u_char td_priority;          /*!< \brief Priority level. 0 is highest priority. */
    u_char *td_memory;           /*!< \brief Pointer to heap memory used for stack. */
    NUTHANDLE td_timer;          /*!< \brief Event timer. */
    volatile NUTHANDLE td_queue; /*!< \brief Root entry of the waiting queue. */
};

/******************************************************************************
 *                                                                            *
 *    G L O B A L   V A R I A B L E S   -   N O   I N I T I A L I Z E R S     *
 *                                                                            *
 ******************************************************************************/

#ifdef NUTTHREAD_C
#define EXTERN
#else
#define EXTERN extern
#endif

/*!
 * \brief Currently running thread.
 *
 * Pointer to the NUTTHREADINFO structure of the currently
 * running thread.
 */
EXTERN NUTTHREADINFO * runningThread;

/*!
 * \brief List of all created threads.
 *
 * Linked list of NUTTHREADINFO structures of all threads.
 * New threads are put in front. This list contains at
 * least two threads, the main application thread followed
 * by the idle thread.
 */
EXTERN NUTTHREADINFO * nutThreadList;

/*!
 * \brief List of ready-to-run threads.
 *
 * Priority ordered linked list of NUTTHREADINFO structures
 * of all threads which are ready to run. The idle thread
 * will always remain at the end of this list.
 */
EXTERN NUTTHREADINFO * runQueue;

/******************************************************************************
 *                                                                            *
 *       G L O B A L   V A R I A B L E S   -   I N I T I A L I Z E R S        *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *                   F U N C T I O N   P R O T O T Y P E S                    *
 *                                                                            *
 ******************************************************************************/

#if defined(NUTOS)
NUTHANDLE NutThreadCreate(char *name, void (*fn) (void *), void *arg, size_t stackSize);
u_char NutThreadSetPriority(u_char level);

void NutThreadKill(void);
void NutThreadDestroy(void);
void NutThreadExit(void);

void NutThreadResume(void);
void NutThreadWake(NUTHANDLE timer, NUTHANDLE th);
void NutThreadYield(void);

void NutThreadAddPriQueue(NUTTHREADINFO * td, NUTTHREADINFO * volatile *tqpp);
void NutThreadRemoveQueue(NUTTHREADINFO * td, NUTTHREADINFO * volatile *tqpp);

void NutThreadSwitch(void);
NUTHANDLE GetThreadByName(char *name);

#else
#define NutThreadCreate(name, fn, arg, stackSize)    (0)
#define NutThreadSetPriority(level)                    (64)

#define NutThreadKill()
#define NutThreadDestroy()
#define NutThreadExit()

#define NutThreadResume()
#define NutThreadWake(timer, th)
#define NutThreadYield()

#define NutThreadAddPriQueue(td, tqpp)
#define NutThreadRemoveQueue(td, tqpp)

#define NutThreadSwitch()
#define GetThreadByName(name)                        (0)

#endif

/*!
 * \brief Macro for thread entry definitions.
 */
#define THREAD(threadfn, arg) \
void threadfn(void *arg) __attribute__ ((noreturn)); \
void threadfn(void *arg)

#undef EXTERN

#ifdef __cplusplus
}                       /* End of extern "C" { */
#endif    /* __cplusplus */

#endif

NutTimer.c               。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

/******************************************************************************
 *                                                                            *
 *                         M O D U L E   D E F I N E                          *
 *                                                                            *
 ******************************************************************************/

#define NUTTIMER_C

/******************************************************************************
 *                                                                            *
 *        C O M P I L E R   D E F I N E D   I N C L U D E   F I L E S         *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *            U S E R   D E F I N E D   I N C L U D E   F I L E S             *
 *                                                                            *
 ******************************************************************************/

#include "Common.h"
#include "XCore.h"
#include "XTimer.h"
#include "NutHeap.h"
#include "NutThread.h"
#include "NutTimer.h"
#include "XComm.h"
#ifdef NUTDEBUG
#include "NutDebug.h"
#endif

#if defined(NUTOS)

/******************************************************************************
 *                                                                            *
 *                         L O C A L   D E F I N E S                          *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *                        L O C A L   T Y P E D E F S                         *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *             L O C A L   F U N C T I O N   P R O T O T Y P E S              *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *    L O C A L   I N I T I A L I Z E D   D A T A   D E F I N I T I O N S     *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *    L O C A L   U N I T I A L I Z E D   D A T A   D E F I N I T I O N S     *
 *                                                                            *
 ******************************************************************************/

/*
 * Last processing time of elapsed timers.
 */
static u_long nut_ticks_resume;

/*!
 * \brief System tick counter
 */
volatile u_long nut_ticks;

/*!
 *  \brief Loops per microsecond.
 */
#if defined(NUT_DELAYLOOPS)
volatile u_long nut_delay_loops = NUT_DELAYLOOPS;
#else
volatile u_long nut_delay_loops;
#endif


/*!
 * \brief Return the number of system ticks per second.
 *
 * \return System tick frequency in Hertz.
 */
static u_long NutGetTickClock(void)
{
    return (1000UL / PERIOD_TIMES);
}

/*!
 * \brief Calculate system ticks for a given number of milliseconds.
 */
static u_long NutTimerMillisToTicks(u_long ms)
{
    return (ms * NutGetTickClock()) / 1000;
}

/*!
 * \brief System timer interrupt handler.
 */
static void NutTimerIntr(void *arg)
{
    nut_ticks++;
}

/*!
 * \brief Initialize system timer.
 *
 * This function is automatically called by Nut/OS during system
 * initialization. It calls the hardware dependent layer to initialze
 * the timer hardware and register a timer interrupt handler.
 */
void NutTimerInit(void)
{
//    NutRegisterTimer(NutTimerIntr);
//    NutEnableTimerIrq();
    StartPeriodFunc((PERIODFUNC)NutTimerIntr);

#if !defined(NUT_DELAYLOOPS)
    {
        /* Wait for the next tick. */
        u_long cnt = NutGetTickCount();
        while (cnt == NutGetTickCount());
        /* Wait for the next tick, counting loops. */
        cnt = NutGetTickCount();
        while (cnt == NutGetTickCount()) {
            nut_delay_loops++;
        }
        /*
         * The loop above needs more cycles than the actual delay loop.
         * Apply the correction found by trial and error. Works acceptable
         * with GCC for Ethernut 1 and 3.
         */
        nut_delay_loops *= 103UL;
        nut_delay_loops /= 26UL;
    }
#endif
}

/*!
 * \brief Loop for a specified number of microseconds.
 *
 * This call will not release the CPU and will not switch to another
 * thread. However, interrupts are not disabled and introduce some
 * jitter. Furthermore, unless NUT_DELAYLOOPS is not defined, the
 * deviation may be greater than 10%.
 *
 * If you need exact timing, use timer/counter hardware instead.
 *
 * \param us Delay time in microseconds. Values above 255 milliseconds
 *           may not work.
 *
 * \todo Overflow handling.
 */
void NutMicroDelay(u_long us)
{
    register u_long cnt = nut_delay_loops * us / 1000 / PERIOD_TIMES;

    while (cnt--) {
        _NOP();
    }
}

/*!
 * \brief Loop for a specified number of milliseconds.
 *
 * This call will not release the CPU and will not switch to another
 * thread. Because of absent thread switching, the delay time is more
 * exact than with NutSleep().
 *
 * \param ms Delay time in milliseconds, maximum is 255.
 *
 * \deprecated New applications should use NutMicroDelay().
 */
void NutDelay(u_char ms)
{
    NutMicroDelay((u_long)ms * 1000);
}

/*!
 * \brief Insert a new timer in the global timer list.
 *
 * Applications should not call this function.
 *
 * \param tn Pointer to the timer structure to insert.
 *
 * \todo Make this local function static.
 */
void NutTimerInsert(NUTTIMERINFO * tn)
{
    NUTTIMERINFO *tnp;

    tn->tn_prev = NULL;
    for (tnp = nutTimerList; tnp; tnp = tnp->tn_next) {
        if (tn->tn_ticks_left < tnp->tn_ticks_left) {
            tnp->tn_ticks_left -= tn->tn_ticks_left;
            break;
        }
        tn->tn_ticks_left -= tnp->tn_ticks_left;
        tn->tn_prev = tnp;
    }
    tn->tn_next = tnp;
    if (tn->tn_next) {
        tn->tn_next->tn_prev = tn;
    }
    if (tn->tn_prev) {
        tn->tn_prev->tn_next = tn;
    }
    else {
        nutTimerList = tn;
    }
}

/*!
 * \brief Process elapsed timers.
 *
 * This routine is called during context switch processing.
 * Applications should not use this function.
 */
void NutTimerProcessElapsed(void)
{
    NUTTIMERINFO *tn;
    u_long ticks;
    u_long ticks_new;

    // calculate ticks since last call
    ticks = NutGetTickCount();
    ticks_new = ticks - nut_ticks_resume;
    nut_ticks_resume = ticks;

    // process timers
    while (nutTimerList && ticks_new){

        tn = nutTimerList;

        // subtract time
        if (ticks_new < tn->tn_ticks_left) {
            tn->tn_ticks_left -= ticks_new;
            ticks_new = 0;
        } else {
            ticks_new -= tn->tn_ticks_left;
            tn->tn_ticks_left = 0;
        }

        // elapsed
        if (tn->tn_ticks_left == 0){

            // callback
            if (tn->tn_callback) {
                (*tn->tn_callback) (tn, (void *) tn->tn_arg);
            }
            // remove from list
            nutTimerList = nutTimerList->tn_next;
            if (nutTimerList) {
                nutTimerList->tn_prev = NULL;
            }
            if ((tn->tn_ticks_left = tn->tn_ticks) == 0) {
                NutHeapFree(tn);
            }
            else {
                NutTimerInsert(tn);
            }
        }
    }
}

/*!
 * \brief Create a new system timer.
 *
 * Applications should not call this function.
 *
 * \param ticks    Specifies the timer interval in system ticks.
 * \param callback Identifies the function to be called on each
 *                 timer interval.
 * \param arg      The argument passed to the callback function.
 * \param flags    If set to TM_ONESHOT, the timer will be stopped
 *                 after the first interval. Set to 0 for periodic
 *                 timers.
 *
 * \return Timer handle if successfull, 0 otherwise. The handle
 *         may be used to release the timer by calling TimerStop.
 *
 * \todo Make this local function static or directly integrate it into
 *       NutTimerStartTicks().
 */
NUTTIMERINFO * NutTimerCreate(u_long ticks, void (*callback) (NUTHANDLE, void *), void *arg, u_char flags)
{
    NUTTIMERINFO *tn;

    tn = NutHeapAlloc(sizeof(NUTTIMERINFO));
    if (tn) {
        tn->tn_ticks_left = ticks + NutGetTickCount() - nut_ticks_resume;

        /*
         * Periodic timers will reload the tick counter on each timer
         * intervall.
         */
        if (flags & TM_ONESHOT) {
            tn->tn_ticks = 0;
        } else {
            tn->tn_ticks = ticks;
        }

        /* Set callback and callback argument. */
        tn->tn_callback = callback;
        tn->tn_arg = arg;
    }
    return tn;
}

/*!
 * \brief Start a system timer.
 *
 * The function returns immediately, while the timer runs asynchronously in
 * the background.
 *
 * The timer counts for a specified number of ticks, then calls the callback
 * routine with a given argument.
 *
 * Even after the timer elapsed, the callback function is not executed
 * before the currently running thread is ready to give up the CPU. Thus,
 * system timers may not fulfill the required accuracy. For precise or
 * high resolution timing, native timer interrupt routines are a better
 * choice.
 *
 * \param ticks    Specifies the timer interval in system ticks.
 * \param callback Identifies the function to be called on each
 *                 timer interval.
 * \param arg      The argument passed to the callback function.
 * \param flags    If set to TM_ONESHOT, the timer will be stopped
 *                 after the first interval. Set to 0 for periodic
 *                 timers.
 *
 * \return Timer handle if successfull, 0 otherwise. The handle
 *         may be used to stop the timer by calling TimerStop.
 */
NUTHANDLE NutTimerStartTicks(u_long ticks, void (*callback) (NUTHANDLE, void *), void *arg, u_char flags)
{
    NUTTIMERINFO *tn;

    tn = NutTimerCreate( ticks, callback, arg, flags);
    if (tn) {
        /* Add the timer to the list. */
        NutTimerInsert(tn);
    }
    return tn;
}

/*!
 * \brief Start a system timer.
 *
 * The function returns immediately, while the timer runs
 * asynchronously in the background.
 *
 * The timer counts for a specified number of milliseconds,
 * then calls the callback routine with a given argument.
 *
 * Even after the timer elapsed, the callback function is not executed
 * before the currently running thread is ready to give up the CPU. Thus,
 * system timers may not fulfill the required accuracy. For precise or
 * high resolution timing, native timer interrupt routines are a better
 * choice.
 *
 * \param ms       Specifies the timer interval in milliseconds. The
 *                 resolution is limited to the granularity of the system
 *                 timer.
 * \param callback Identifies the function to be called on each
 *                 timer interval.
 * \param arg      The argument passed to the callback function.
 * \param flags    If set to TM_ONESHOT, the timer will be stopped
 *                 after the first interval. Set to 0 for periodic
 *                 timers.
 *
 * \return Timer handle if successfull, 0 otherwise. The handle
 *         may be used to stop the timer by calling TimerStop.
 */
NUTHANDLE NutTimerStart(u_long ms, void (*callback) (NUTHANDLE, void *), void *arg, u_char flags)
{
    return NutTimerStartTicks(NutTimerMillisToTicks(ms), callback, arg, flags);
}

/*!
 * \brief Temporarily suspends the current thread.
 *
 * Causes the current thread to wait for a specified interval or,
 * if the specified interval is zero, to give up the CPU for
 * another thread with higher or same priority.
 *
 * This function may switch to another application thread, that
 * got the same or a higher priority and is ready to run.
 *
 * \note Threads may sleep longer than the specified number of
 *       milliseconds, depending on the number of threads
 *       with higher or equal priority, which are ready to run.
 *
 * \param ms Milliseconds to sleep. If 0, the current thread will not
 *           sleep, but may give up the CPU. The resolution is limited
 *           to the granularity of the system timer.
 *
 * \todo Code size can be reduced by trying to create the timer before
 *       removing the thread from the run queue.
 */
void NutSleep(u_long ms)
{
    if (ms) {

        /* remove running thread from runQueue */
        NutThreadRemoveQueue(runningThread, &runQueue);
        runningThread->td_state = TDS_SLEEP;

        if ((runningThread->td_timer = NutTimerStart(ms, NutThreadWake, runningThread, TM_ONESHOT)) != 0) {
            NutThreadResume();
        } else
        {
            /* timer creation failed, restore queues */
            runningThread->td_queue = &runQueue;
            runningThread->td_qnxt  = runQueue;
            runningThread->td_state = TDS_RUNNING;
            runQueue = runningThread;
        }
    } else
        NutThreadYield();
}

/*!
 * \brief Stop a specified timer.
 *
 * Only periodic timers need to be stopped. One-shot timers
 * are automatically stopped by the timer management after
 * ther first timer interval. Anyway, long running one-shot
 * timers may be stopped to release the occupied memory.
 *
 * \param handle Identifies the timer to be stopped. This handle must
 *               have been created by calling NutTimerStart() or
 *               NutTimerStartTicks().
 */
void NutTimerStop(NUTHANDLE handle)
{
    NUTTIMERINFO *tn = (NUTTIMERINFO *)handle;

    /* Disable periodic operation and callback. */
    tn->tn_ticks = 0;
    tn->tn_callback = NULL;
    /* If not already elapsed, expire the timer. */
    if (tn->tn_ticks_left) {
        if (tn->tn_prev) {
            tn->tn_prev->tn_next = tn->tn_next;
        }
        else {
            nutTimerList = tn->tn_next;
        }
        if (tn->tn_next) {
            tn->tn_next->tn_prev = tn->tn_prev;
            tn->tn_next->tn_ticks_left += tn->tn_ticks_left;
        }
        tn->tn_ticks_left = 0;
        NutTimerInsert(tn);
    }
}

/*!
 * \brief Return the number of system timer ticks.
 *
 * This function returns the number of system ticks since the system was
 * started.
 *
 * \return Number of ticks.
 */
u_long NutGetTickCount(void)
{
    u_long rc;

    NutEnterCritical();
    rc = nut_ticks;
    NutExitCritical();

    return rc;
}

/*!
 * \brief Return the seconds counter value.
 *
 * This function returns the value of a counter, which is incremented
 * every second. During system start, the counter is cleared to zero.
 *
 * \note There is intentionally no provision to modify the seconds counter.
 *       Callers can rely on a continuous update and use this value for
 *       system tick independend timeout calculations. Applications,
 *       which want to use this counter for date and time functions,
 *       should use an offset value.
 *
 * \return Value of the seconds counter.
 */
u_long NutGetSeconds(void)
{
    return NutGetTickCount() / NutGetTickClock();
}

/*!
 * \brief Return the milliseconds counter value.
 *
 * This function returns the value of a counter, which is incremented
 * every system timer tick. During system start, the counter is cleared
 * to zero and will overflow with the 32 bit tick counter (4294967296).
 * With the default 1024 ticks/s this will happen after 49.71 days.
 * The resolution is also given by the system ticks.
 *
 * \note There is intentionally no provision to modify the seconds counter.
 *       Callers can rely on a continuous update and use this value for
 *       system tick independend timeout calculations.
 *       Depending on
 *
 * \return Value of the seconds counter.
 */
u_long NutGetMillis(void)
{
    // carefully stay within 32 bit values
    u_long ticks   = NutGetTickCount();
    u_long seconds = ticks / NutGetTickClock();
    ticks         -= seconds * NutGetTickClock();
    return seconds * 1000 + (ticks * 1000 ) / NutGetTickClock();
}

#endif

NutTimer.h              。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

#ifndef NUTTIMER_H

/******************************************************************************
 *                                                                            *
 *                         M O D U L E   D E F I N E                          *
 *                                                                            *
 ******************************************************************************/

#define NUTTIMER_H

/******************************************************************************
 *                                                                            *
 *        C O M P I L E R   D E F I N E D   I N C L U D E   F I L E S         *
 *                                                                            *
 ******************************************************************************/

/******************************************************************************
 *                                                                            *
 *            U S E R   D E F I N E D   I N C L U D E   F I L E S             *
 *                                                                            *
 ******************************************************************************/

#ifdef __cplusplus
extern "C" {            /* Assume C declarations for C++ */
#endif    /* __cplusplus */

/******************************************************************************
 *                                                                            *
 *                        G L O B A L   D E F I N E S                         *
 *                                                                            *
 ******************************************************************************/

#define TM_ONESHOT  0x01

/******************************************************************************
 *                                                                            *
 *                 S T R U C T U R E   D E F I N I T I O N S                  *
 *                                                                            *
 ******************************************************************************/

/*!
 * \brief Timer type.
 */
typedef struct _NUTTIMERINFO NUTTIMERINFO;

/*!
 * \struct _NUTTIMERINFO timer.h sys/timer.h
 * \brief Timer information structure.
 */
struct _NUTTIMERINFO {
    /*! \brief Link to next timer. 
     */
    NUTTIMERINFO *tn_next;          
    /*! \brief Link to previous timer. 
     */
    NUTTIMERINFO *tn_prev;          
    /*! \brief Number of system ticks. 
     *  Set to zero on one-shot timers.
     */
    u_long tn_ticks;        
    /*! \brief Decremented by one on each system tick intervall. 
     */
    u_long tn_ticks_left;   
    /*! \brief Callback function. 
     */
    void (*tn_callback)(NUTHANDLE, void *);    
    /*! \brief Argument pointer passed to callback function. 
     */
    volatile void *tn_arg;          
};

/******************************************************************************
 *                                                                            *
 *    G L O B A L   V A R I A B L E S   -   N O   I N I T I A L I Z E R S     *
 *                                                                            *
 ******************************************************************************/

#ifdef NUTTIMER_C
#define EXTERN
#else
#define EXTERN extern
#endif

/*!
 * \brief Double linked list of all system timers.
 */
EXTERN NUTTIMERINFO * nutTimerList;

/******************************************************************************
 *                                                                            *
 *       G L O B A L   V A R I A B L E S   -   I N I T I A L I Z E R S        *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *                   F U N C T I O N   P R O T O T Y P E S                    *
 *                                                                            *
 ******************************************************************************/

#if defined(NUTOS)
/*
 * Functions used by the kernel.
 */
void NutTimerInit(void);
NUTTIMERINFO * NutTimerCreate(u_long ticks, void (*callback) (NUTHANDLE, void *), void *arg, u_char flags);
void NutTimerInsert(NUTTIMERINFO * tn);
void NutTimerProcessElapsed(void);

/*
 * API declarations.
 */
void NutSleep(u_long ms);
void NutDelay(u_char ms);
void NutMicroDelay(u_long us);

u_long NutGetTickCount(void);
u_long NutGetSeconds(void);
u_long NutGetMillis(void);

NUTHANDLE NutTimerStart(u_long ms, void (*callback)(NUTHANDLE, void *), void *arg, u_char flags);
NUTHANDLE NutTimerStartTicks(u_long ticks, void (*callback) (NUTHANDLE, void *), void *arg, u_char flags);
void NutTimerStop(NUTHANDLE handle);

#else
#define NutTimerInit()
#define NutTimerCreate(ticks, callback, arg, flags)        (0)
#define NutTimerInsert(tn)
#define NutTimerProcessElapsed()

#define NutDelay(ms)
#define NutSleep(ms)

#define NutGetTickCount()                                (0)
#define NutGetSeconds()                                    (0)
#define NutGetMillis()                                    (0)

#define NutTimerStart(ms, callback, arg, flags)            (0)
#define NutTimerStartTicks(ticks, callback, arg, flags)    (0)
#define NutTimerStop(handle)

#endif

#undef EXTERN

#ifdef __cplusplus
}                       /* End of extern "C" { */
#endif    /* __cplusplus */

#endif

  • 21
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值