Updated to use external spawn.

Fork of simplelink_V2 by David Fletcher

cc3100_spawn.cpp

Committer:
dflet
Date:
2015-06-06
Revision:
1:9b68e650b3f6
Parent:
0:1a07906111ec

File content as of revision 1:9b68e650b3f6:

/*
 * spawn.c - CC31xx/CC32xx Host Driver Implementation
 *
 * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
 *
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *    Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 *    Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the
 *    distribution.
 *
 *    Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
*/



/*****************************************************************************/
/* Include files                                                             */
/*****************************************************************************/
#include "cc3100_simplelink.h"

#include "cc3100_spawn.h"

#if (defined (SL_PLATFORM_MULTI_THREADED)) && (!defined (SL_PLATFORM_EXTERNAL_SPAWN))

namespace mbed_cc3100 {

#define _SL_MAX_INTERNAL_SPAWN_ENTRIES      10


typedef struct _SlInternalSpawnEntry_t {
    _SlSpawnEntryFunc_t 		        pEntry;
    void* 						        pValue;
    struct _SlInternalSpawnEntry_t*     pNext;
} _SlInternalSpawnEntry_t;

typedef struct {
    _SlInternalSpawnEntry_t     SpawnEntries[_SL_MAX_INTERNAL_SPAWN_ENTRIES];
    _SlInternalSpawnEntry_t*    pFree;
    _SlInternalSpawnEntry_t*    pWaitForExe;
    _SlInternalSpawnEntry_t*    pLastInWaitList;
    _SlSyncObj_t                SyncObj;
    _SlLockObj_t                LockObj;
} _SlInternalSpawnCB_t;

_SlInternalSpawnCB_t g_SlInternalSpawnCB;

cc3100_spawn::cc3100_spawn()
{

}

cc3100_spawn::~cc3100_spawn()
{

}


void cc3100_spawn::_SlInternalSpawnTaskEntry()
{
    int16_t                     i;
    _SlInternalSpawnEntry_t*    pEntry;
    uint8_t                     LastEntry;

    /* create and lock the locking object. lock in order to avoid race condition
        on the first creation */
    sl_LockObjCreate(&g_SlInternalSpawnCB.LockObj,"SlSpawnProtect");
    sl_LockObjLock(&g_SlInternalSpawnCB.LockObj,SL_OS_NO_WAIT);

    /* create and clear the sync object */
    sl_SyncObjCreate(&g_SlInternalSpawnCB.SyncObj,"SlSpawnSync");
    sl_SyncObjWait(&g_SlInternalSpawnCB.SyncObj,SL_OS_NO_WAIT);

    g_SlInternalSpawnCB.pFree = &g_SlInternalSpawnCB.SpawnEntries[0];
    g_SlInternalSpawnCB.pWaitForExe = NULL;
    g_SlInternalSpawnCB.pLastInWaitList = NULL;

    /* create the link list between the entries */
    for (i=0 ; i<_SL_MAX_INTERNAL_SPAWN_ENTRIES - 1 ; i++) {
        g_SlInternalSpawnCB.SpawnEntries[i].pNext = &g_SlInternalSpawnCB.SpawnEntries[i+1];
        g_SlInternalSpawnCB.SpawnEntries[i].pEntry = NULL;
    }
    g_SlInternalSpawnCB.SpawnEntries[i].pNext = NULL;

    _SlDrvObjUnLock(&g_SlInternalSpawnCB.LockObj);


    /* here we ready to execute entries */

    while (TRUE) {
        sl_SyncObjWait(&g_SlInternalSpawnCB.SyncObj,SL_OS_WAIT_FOREVER);
        /* go over all entries that already waiting for execution */
        LastEntry = FALSE;
        do {
            /* get entry to execute */
            _SlDrvObjLockWaitForever(&g_SlInternalSpawnCB.LockObj);

            pEntry = g_SlInternalSpawnCB.pWaitForExe;
            if ( NULL == pEntry ) {
                _SlDrvObjUnLock(&g_SlInternalSpawnCB.LockObj);
                break;
            }
            g_SlInternalSpawnCB.pWaitForExe = pEntry->pNext;
            if (pEntry == g_SlInternalSpawnCB.pLastInWaitList) {
                g_SlInternalSpawnCB.pLastInWaitList = NULL;
                LastEntry = TRUE;
            }

            _SlDrvObjUnLock(&g_SlInternalSpawnCB.LockObj);


            /* pEntry could be null in case that the sync was already set by some
               of the entries during execution of earlier entry */
            if (NULL != pEntry) {
                pEntry->pEntry(pEntry->pValue);
                /* free the entry */
                _SlDrvObjLockWaitForever(&g_SlInternalSpawnCB.LockObj);

                pEntry->pNext = g_SlInternalSpawnCB.pFree;
                g_SlInternalSpawnCB.pFree = pEntry;


                if (NULL != g_SlInternalSpawnCB.pWaitForExe) {
                    /* new entry received meanwhile */
                    LastEntry = FALSE;
                }

                _SlDrvObjUnLock(&g_SlInternalSpawnCB.LockObj);

            }

        } while (!LastEntry);
    }
}


int16_t cc3100_spawn::_SlInternalSpawn(_SlSpawnEntryFunc_t pEntry , void* pValue , uint32_t flags)
{
    int16_t                         Res = 0;
    _SlInternalSpawnEntry_t*    pSpawnEntry;

    if (NULL == pEntry) {
        Res = -1;
    } else {
         _SlDrvObjLockWaitForever(&g_SlInternalSpawnCB.LockObj);

        pSpawnEntry = g_SlInternalSpawnCB.pFree;
        g_SlInternalSpawnCB.pFree = pSpawnEntry->pNext;

        pSpawnEntry->pEntry = pEntry;
        pSpawnEntry->pValue = pValue;
        pSpawnEntry->pNext = NULL;

        if (NULL == g_SlInternalSpawnCB.pWaitForExe) {
            g_SlInternalSpawnCB.pWaitForExe = pSpawnEntry;
            g_SlInternalSpawnCB.pLastInWaitList = pSpawnEntry;
        } else {
            g_SlInternalSpawnCB.pLastInWaitList->pNext = pSpawnEntry;
            g_SlInternalSpawnCB.pLastInWaitList = pSpawnEntry;
        }

        _SlDrvObjUnLock(&g_SlInternalSpawnCB.LockObj);
        
        /* this sync is called after releasing the lock object to avoid unnecessary context switches */
        _SlDrvSyncObjSignal(&g_SlInternalSpawnCB.SyncObj);
    }

    return Res;
}

}//namespace mbed_cc3100

#endif//SL_PLATFORM_MULTI_THREADED